aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/session
diff options
context:
space:
mode:
authorFlorin Coras <fcoras@cisco.com>2017-07-16 17:12:15 -0700
committerDave Barach <openvpp@barachs.net>2017-07-25 11:17:20 +0000
commit04e5344a358a9ad42d896486d2d226149fd326f4 (patch)
tree74727757d79e1e711f3a8c67016ba2b04eea6c91 /src/vnet/session
parentf8d84901e4f82c54545030a881da9aded659baf9 (diff)
Cleanup/refactor session layer code
Change-Id: Ica99e8cb919fca6b069c37c969d60e8ccc2c6bf9 Signed-off-by: Florin Coras <fcoras@cisco.com>
Diffstat (limited to 'src/vnet/session')
-rw-r--r--src/vnet/session/hashes.c28
-rw-r--r--src/vnet/session/session.c506
-rw-r--r--src/vnet/session/session.h164
-rw-r--r--src/vnet/session/session_lookup.c620
-rw-r--r--src/vnet/session/session_lookup.h101
-rw-r--r--src/vnet/session/session_node.c (renamed from src/vnet/session/node.c)0
-rw-r--r--src/vnet/session/stream_session.h98
-rw-r--r--src/vnet/session/transport.c64
-rw-r--r--src/vnet/session/transport.h174
-rw-r--r--src/vnet/session/transport_interface.c106
-rw-r--r--src/vnet/session/transport_interface.h82
11 files changed, 1044 insertions, 899 deletions
diff --git a/src/vnet/session/hashes.c b/src/vnet/session/hashes.c
deleted file mode 100644
index 1808dd73f90..00000000000
--- a/src/vnet/session/hashes.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/** Generate typed init functions for multiple hash table styles... */
-
-#include <vppinfra/bihash_16_8.h>
-#include <vppinfra/bihash_template.h>
-
-#include <vppinfra/bihash_template.c>
-
-#undef __included_bihash_template_h__
-
-#include <vppinfra/bihash_48_8.h>
-#include <vppinfra/bihash_template.h>
-
-#include <vppinfra/bihash_template.c>
diff --git a/src/vnet/session/session.c b/src/vnet/session/session.c
index 09bc00e745a..48000a6fee6 100644
--- a/src/vnet/session/session.c
+++ b/src/vnet/session/session.c
@@ -18,455 +18,15 @@
*/
#include <vnet/session/session.h>
+#include <vnet/session/session_debug.h>
+#include <vnet/session/application.h>
#include <vlibmemory/api.h>
#include <vnet/dpo/load_balance.h>
#include <vnet/fib/ip4_fib.h>
-#include <vnet/session/application.h>
#include <vnet/tcp/tcp.h>
-#include <vnet/session/session_debug.h>
-
-/**
- * Per-type vector of transport protocol virtual function tables
- */
-static transport_proto_vft_t *tp_vfts;
session_manager_main_t session_manager_main;
-
-transport_connection_t *
-stream_session_lookup_half_open (transport_connection_t * tc)
-{
- session_manager_main_t *smm = &session_manager_main;
- session_kv4_t kv4;
- int rv;
- if (tc->is_ip4)
- {
- make_v4_ss_kv_from_tc (&kv4, tc);
- rv = clib_bihash_search_inline_16_8 (&smm->v4_half_open_hash, &kv4);
- if (rv == 0)
- return tp_vfts[tc->proto].get_half_open (kv4.value & 0xFFFFFFFFULL);
- }
- return 0;
-}
-
-/*
- * Session lookup key; (src-ip, dst-ip, src-port, dst-port, session-type)
- * Value: (owner thread index << 32 | session_index);
- */
-void
-stream_session_table_add_for_tc (transport_connection_t * tc, u64 value)
-{
- session_manager_main_t *smm = &session_manager_main;
- session_kv4_t kv4;
- session_kv6_t kv6;
-
- switch (tc->proto)
- {
- case SESSION_TYPE_IP4_UDP:
- case SESSION_TYPE_IP4_TCP:
- make_v4_ss_kv_from_tc (&kv4, tc);
- kv4.value = value;
- clib_bihash_add_del_16_8 (&smm->v4_session_hash, &kv4, 1 /* is_add */ );
- break;
- case SESSION_TYPE_IP6_UDP:
- case SESSION_TYPE_IP6_TCP:
- make_v6_ss_kv_from_tc (&kv6, tc);
- kv6.value = value;
- clib_bihash_add_del_48_8 (&smm->v6_session_hash, &kv6, 1 /* is_add */ );
- break;
- default:
- clib_warning ("Session type not supported");
- ASSERT (0);
- }
-}
-
-void
-stream_session_table_add (session_manager_main_t * smm, stream_session_t * s,
- u64 value)
-{
- transport_connection_t *tc;
-
- tc = tp_vfts[s->session_type].get_connection (s->connection_index,
- s->thread_index);
- stream_session_table_add_for_tc (tc, value);
-}
-
-static void
-stream_session_half_open_table_add (session_type_t sst,
- transport_connection_t * tc, u64 value)
-{
- session_manager_main_t *smm = &session_manager_main;
- session_kv4_t kv4;
- session_kv6_t kv6;
-
- switch (sst)
- {
- case SESSION_TYPE_IP4_UDP:
- case SESSION_TYPE_IP4_TCP:
- make_v4_ss_kv_from_tc (&kv4, tc);
- kv4.value = value;
- clib_bihash_add_del_16_8 (&smm->v4_half_open_hash, &kv4,
- 1 /* is_add */ );
- break;
- case SESSION_TYPE_IP6_UDP:
- case SESSION_TYPE_IP6_TCP:
- make_v6_ss_kv_from_tc (&kv6, tc);
- kv6.value = value;
- clib_bihash_add_del_48_8 (&smm->v6_half_open_hash, &kv6,
- 1 /* is_add */ );
- break;
- default:
- clib_warning ("Session type not supported");
- ASSERT (0);
- }
-}
-
-int
-stream_session_table_del_for_tc (transport_connection_t * tc)
-{
- session_manager_main_t *smm = &session_manager_main;
- session_kv4_t kv4;
- session_kv6_t kv6;
- switch (tc->proto)
- {
- case SESSION_TYPE_IP4_UDP:
- case SESSION_TYPE_IP4_TCP:
- make_v4_ss_kv_from_tc (&kv4, tc);
- return clib_bihash_add_del_16_8 (&smm->v4_session_hash, &kv4,
- 0 /* is_add */ );
- break;
- case SESSION_TYPE_IP6_UDP:
- case SESSION_TYPE_IP6_TCP:
- make_v6_ss_kv_from_tc (&kv6, tc);
- return clib_bihash_add_del_48_8 (&smm->v6_session_hash, &kv6,
- 0 /* is_add */ );
- break;
- default:
- clib_warning ("Session type not supported");
- ASSERT (0);
- }
-
- return 0;
-}
-
-static int
-stream_session_table_del (session_manager_main_t * smm, stream_session_t * s)
-{
- transport_connection_t *ts;
-
- ts = tp_vfts[s->session_type].get_connection (s->connection_index,
- s->thread_index);
- return stream_session_table_del_for_tc (ts);
-}
-
-static void
-stream_session_half_open_table_del (session_manager_main_t * smm, u8 sst,
- transport_connection_t * tc)
-{
- session_kv4_t kv4;
- session_kv6_t kv6;
-
- switch (sst)
- {
- case SESSION_TYPE_IP4_UDP:
- case SESSION_TYPE_IP4_TCP:
- make_v4_ss_kv_from_tc (&kv4, tc);
- clib_bihash_add_del_16_8 (&smm->v4_half_open_hash, &kv4,
- 0 /* is_add */ );
- break;
- case SESSION_TYPE_IP6_UDP:
- case SESSION_TYPE_IP6_TCP:
- make_v6_ss_kv_from_tc (&kv6, tc);
- clib_bihash_add_del_48_8 (&smm->v6_half_open_hash, &kv6,
- 0 /* is_add */ );
- break;
- default:
- clib_warning ("Session type not supported");
- ASSERT (0);
- }
-}
-
-stream_session_t *
-stream_session_lookup_listener4 (ip4_address_t * lcl, u16 lcl_port, u8 proto)
-{
- session_manager_main_t *smm = &session_manager_main;
- session_kv4_t kv4;
- int rv;
-
- make_v4_listener_kv (&kv4, lcl, lcl_port, proto);
- rv = clib_bihash_search_inline_16_8 (&smm->v4_session_hash, &kv4);
- if (rv == 0)
- return pool_elt_at_index (smm->listen_sessions[proto], (u32) kv4.value);
-
- /* Zero out the lcl ip */
- kv4.key[0] = 0;
- rv = clib_bihash_search_inline_16_8 (&smm->v4_session_hash, &kv4);
- if (rv == 0)
- return pool_elt_at_index (smm->listen_sessions[proto], kv4.value);
-
- return 0;
-}
-
-/** Looks up a session based on the 5-tuple passed as argument.
- *
- * First it tries to find an established session, if this fails, it tries
- * finding a listener session if this fails, it tries a lookup with a
- * wildcarded local source (listener bound to all interfaces)
- */
-stream_session_t *
-stream_session_lookup4 (ip4_address_t * lcl, ip4_address_t * rmt,
- u16 lcl_port, u16 rmt_port, u8 proto)
-{
- session_manager_main_t *smm = &session_manager_main;
- session_kv4_t kv4;
- stream_session_t *s;
- int rv;
-
- /* Lookup session amongst established ones */
- make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
- rv = clib_bihash_search_inline_16_8 (&smm->v4_session_hash, &kv4);
- if (rv == 0)
- return stream_session_get_from_handle (kv4.value);
-
- /* If nothing is found, check if any listener is available */
- if ((s = stream_session_lookup_listener4 (lcl, lcl_port, proto)))
- return s;
-
- /* Finally, try half-open connections */
- rv = clib_bihash_search_inline_16_8 (&smm->v4_half_open_hash, &kv4);
- if (rv == 0)
- return stream_session_get_from_handle (kv4.value);
- return 0;
-}
-
-stream_session_t *
-stream_session_lookup_listener6 (ip6_address_t * lcl, u16 lcl_port, u8 proto)
-{
- session_manager_main_t *smm = &session_manager_main;
- session_kv6_t kv6;
- int rv;
-
- make_v6_listener_kv (&kv6, lcl, lcl_port, proto);
- rv = clib_bihash_search_inline_48_8 (&smm->v6_session_hash, &kv6);
- if (rv == 0)
- return pool_elt_at_index (smm->listen_sessions[proto], kv6.value);
-
- /* Zero out the lcl ip */
- kv6.key[0] = kv6.key[1] = 0;
- rv = clib_bihash_search_inline_48_8 (&smm->v6_session_hash, &kv6);
- if (rv == 0)
- return pool_elt_at_index (smm->listen_sessions[proto], kv6.value);
-
- return 0;
-}
-
-/* Looks up a session based on the 5-tuple passed as argument.
- * First it tries to find an established session, if this fails, it tries
- * finding a listener session if this fails, it tries a lookup with a
- * wildcarded local source (listener bound to all interfaces) */
-stream_session_t *
-stream_session_lookup6 (ip6_address_t * lcl, ip6_address_t * rmt,
- u16 lcl_port, u16 rmt_port, u8 proto)
-{
- session_manager_main_t *smm = vnet_get_session_manager_main ();
- session_kv6_t kv6;
- stream_session_t *s;
- int rv;
-
- make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
- rv = clib_bihash_search_inline_48_8 (&smm->v6_session_hash, &kv6);
- if (rv == 0)
- return stream_session_get_from_handle (kv6.value);
-
- /* If nothing is found, check if any listener is available */
- if ((s = stream_session_lookup_listener6 (lcl, lcl_port, proto)))
- return s;
-
- /* Finally, try half-open connections */
- rv = clib_bihash_search_inline_48_8 (&smm->v6_half_open_hash, &kv6);
- if (rv == 0)
- return stream_session_get_from_handle (kv6.value);
- return 0;
-}
-
-stream_session_t *
-stream_session_lookup_listener (ip46_address_t * lcl, u16 lcl_port, u8 proto)
-{
- switch (proto)
- {
- case SESSION_TYPE_IP4_UDP:
- case SESSION_TYPE_IP4_TCP:
- return stream_session_lookup_listener4 (&lcl->ip4, lcl_port, proto);
- break;
- case SESSION_TYPE_IP6_UDP:
- case SESSION_TYPE_IP6_TCP:
- return stream_session_lookup_listener6 (&lcl->ip6, lcl_port, proto);
- break;
- }
- return 0;
-}
-
-static u64
-stream_session_half_open_lookup (session_manager_main_t * smm,
- ip46_address_t * lcl, ip46_address_t * rmt,
- u16 lcl_port, u16 rmt_port, u8 proto)
-{
- session_kv4_t kv4;
- session_kv6_t kv6;
- int rv;
-
- switch (proto)
- {
- case SESSION_TYPE_IP4_UDP:
- case SESSION_TYPE_IP4_TCP:
- make_v4_ss_kv (&kv4, &lcl->ip4, &rmt->ip4, lcl_port, rmt_port, proto);
- rv = clib_bihash_search_inline_16_8 (&smm->v4_half_open_hash, &kv4);
-
- if (rv == 0)
- return kv4.value;
-
- return (u64) ~ 0;
- break;
- case SESSION_TYPE_IP6_UDP:
- case SESSION_TYPE_IP6_TCP:
- make_v6_ss_kv (&kv6, &lcl->ip6, &rmt->ip6, lcl_port, rmt_port, proto);
- rv = clib_bihash_search_inline_48_8 (&smm->v6_half_open_hash, &kv6);
-
- if (rv == 0)
- return kv6.value;
-
- return (u64) ~ 0;
- break;
- }
- return 0;
-}
-
-transport_connection_t *
-stream_session_lookup_transport_wt4 (ip4_address_t * lcl, ip4_address_t * rmt,
- u16 lcl_port, u16 rmt_port, u8 proto,
- u32 my_thread_index)
-{
- session_manager_main_t *smm = &session_manager_main;
- session_kv4_t kv4;
- stream_session_t *s;
- int rv;
-
- /* Lookup session amongst established ones */
- make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
- rv = clib_bihash_search_inline_16_8 (&smm->v4_session_hash, &kv4);
- if (rv == 0)
- {
- s = stream_session_get_tsi (kv4.value, my_thread_index);
-
- return tp_vfts[s->session_type].get_connection (s->connection_index,
- my_thread_index);
- }
-
- /* If nothing is found, check if any listener is available */
- s = stream_session_lookup_listener4 (lcl, lcl_port, proto);
- if (s)
- return tp_vfts[s->session_type].get_listener (s->connection_index);
-
- /* Finally, try half-open connections */
- rv = clib_bihash_search_inline_16_8 (&smm->v4_half_open_hash, &kv4);
- if (rv == 0)
- return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF);
- return 0;
-}
-
-transport_connection_t *
-stream_session_lookup_transport4 (ip4_address_t * lcl, ip4_address_t * rmt,
- u16 lcl_port, u16 rmt_port, u8 proto)
-{
- session_manager_main_t *smm = &session_manager_main;
- session_kv4_t kv4;
- stream_session_t *s;
- int rv;
-
- /* Lookup session amongst established ones */
- make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
- rv = clib_bihash_search_inline_16_8 (&smm->v4_session_hash, &kv4);
- if (rv == 0)
- {
- s = stream_session_get_from_handle (kv4.value);
- return tp_vfts[s->session_type].get_connection (s->connection_index,
- s->thread_index);
- }
-
- /* If nothing is found, check if any listener is available */
- s = stream_session_lookup_listener4 (lcl, lcl_port, proto);
- if (s)
- return tp_vfts[s->session_type].get_listener (s->connection_index);
-
- /* Finally, try half-open connections */
- rv = clib_bihash_search_inline_16_8 (&smm->v4_half_open_hash, &kv4);
- if (rv == 0)
- return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF);
- return 0;
-}
-
-transport_connection_t *
-stream_session_lookup_transport_wt6 (ip6_address_t * lcl, ip6_address_t * rmt,
- u16 lcl_port, u16 rmt_port, u8 proto,
- u32 my_thread_index)
-{
- session_manager_main_t *smm = &session_manager_main;
- stream_session_t *s;
- session_kv6_t kv6;
- int rv;
-
- make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
- rv = clib_bihash_search_inline_48_8 (&smm->v6_session_hash, &kv6);
- if (rv == 0)
- {
- s = stream_session_get_tsi (kv6.value, my_thread_index);
-
- return tp_vfts[s->session_type].get_connection (s->connection_index,
- my_thread_index);
- }
-
- /* If nothing is found, check if any listener is available */
- s = stream_session_lookup_listener6 (lcl, lcl_port, proto);
- if (s)
- return tp_vfts[s->session_type].get_listener (s->connection_index);
-
- /* Finally, try half-open connections */
- rv = clib_bihash_search_inline_48_8 (&smm->v6_half_open_hash, &kv6);
- if (rv == 0)
- return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF);
-
- return 0;
-}
-
-transport_connection_t *
-stream_session_lookup_transport6 (ip6_address_t * lcl, ip6_address_t * rmt,
- u16 lcl_port, u16 rmt_port, u8 proto)
-{
- session_manager_main_t *smm = &session_manager_main;
- stream_session_t *s;
- session_kv6_t kv6;
- int rv;
-
- make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
- rv = clib_bihash_search_inline_48_8 (&smm->v6_session_hash, &kv6);
- if (rv == 0)
- {
- s = stream_session_get_from_handle (kv6.value);
- return tp_vfts[s->session_type].get_connection (s->connection_index,
- s->thread_index);
- }
-
- /* If nothing is found, check if any listener is available */
- s = stream_session_lookup_listener6 (lcl, lcl_port, proto);
- if (s)
- return tp_vfts[s->session_type].get_listener (s->connection_index);
-
- /* Finally, try half-open connections */
- rv = clib_bihash_search_inline_48_8 (&smm->v6_half_open_hash, &kv6);
- if (rv == 0)
- return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF);
-
- return 0;
-}
+extern transport_proto_vft_t *tp_vfts;
int
stream_session_create_i (segment_manager_t * sm, transport_connection_t * tc,
@@ -797,16 +357,15 @@ int
stream_session_connect_notify (transport_connection_t * tc, u8 sst,
u8 is_fail)
{
- session_manager_main_t *smm = &session_manager_main;
application_t *app;
stream_session_t *new_s = 0;
u64 handle;
u32 api_context = 0;
int error = 0;
- handle = stream_session_half_open_lookup (smm, &tc->lcl_ip, &tc->rmt_ip,
- tc->lcl_port, tc->rmt_port,
- tc->proto);
+ handle = stream_session_half_open_lookup_handle (&tc->lcl_ip, &tc->rmt_ip,
+ tc->lcl_port, tc->rmt_port,
+ tc->proto);
if (handle == HALF_OPEN_LOOKUP_INVALID_VALUE)
{
clib_warning ("This can't be good!");
@@ -847,7 +406,7 @@ stream_session_connect_notify (transport_connection_t * tc, u8 sst,
}
/* Cleanup session lookup */
- stream_session_half_open_table_del (smm, sst, tc);
+ stream_session_half_open_table_del (sst, tc);
return error;
}
@@ -891,7 +450,7 @@ stream_session_delete (stream_session_t * s)
int rv;
/* Delete from the main lookup table. */
- if ((rv = stream_session_table_del (smm, s)))
+ if ((rv = stream_session_table_del (s)))
clib_warning ("hash delete error, rv %d", rv);
/* Cleanup fifo segments */
@@ -986,14 +545,14 @@ stream_session_accept (transport_connection_t * tc, u32 listener_index,
*/
int
stream_session_open (u32 app_index, session_type_t st,
- transport_endpoint_t * tep,
+ transport_endpoint_t * rmt,
transport_connection_t ** res)
{
transport_connection_t *tc;
int rv;
u64 handle;
- rv = tp_vfts[st].open (&tep->ip, tep->port);
+ rv = tp_vfts[st].open (rmt);
if (rv < 0)
{
clib_warning ("Transport failed to open connection.");
@@ -1030,7 +589,7 @@ stream_session_listen (stream_session_t * s, transport_endpoint_t * tep)
u32 tci;
/* Transport bind/listen */
- tci = tp_vfts[s->session_type].bind (s->session_index, &tep->ip, tep->port);
+ tci = tp_vfts[s->session_type].bind (s->session_index, tep);
if (tci == (u32) ~ 0)
return -1;
@@ -1132,41 +691,18 @@ stream_session_disconnect (stream_session_t * s)
void
stream_session_cleanup (stream_session_t * s)
{
- session_manager_main_t *smm = &session_manager_main;
int rv;
s->session_state = SESSION_STATE_CLOSED;
/* Delete from the main lookup table to avoid more enqueues */
- rv = stream_session_table_del (smm, s);
+ rv = stream_session_table_del (s);
if (rv)
clib_warning ("hash delete error, rv %d", rv);
tp_vfts[s->session_type].cleanup (s->connection_index, s->thread_index);
}
-void
-session_register_transport (u8 type, const transport_proto_vft_t * vft)
-{
- session_manager_main_t *smm = vnet_get_session_manager_main ();
-
- vec_validate (tp_vfts, type);
- tp_vfts[type] = *vft;
-
- /* If an offset function is provided, then peek instead of dequeue */
- smm->session_tx_fns[type] =
- (vft->tx_fifo_offset) ? session_tx_fifo_peek_and_snd :
- session_tx_fifo_dequeue_and_snd;
-}
-
-transport_proto_vft_t *
-session_get_transport_vft (u8 type)
-{
- if (type >= vec_len (tp_vfts))
- return 0;
- return &tp_vfts[type];
-}
-
/**
* Allocate vpp event queue (once) per worker thread
*/
@@ -1269,19 +805,7 @@ session_manager_main_enable (vlib_main_t * vm)
for (i = 0; i < smm->preallocated_sessions; i++)
pool_put_index (smm->sessions[0], i);
- clib_bihash_init_16_8 (&smm->v4_session_hash, "v4 session table",
- 200000 /* $$$$ config parameter nbuckets */ ,
- (64 << 20) /*$$$ config parameter table size */ );
- clib_bihash_init_48_8 (&smm->v6_session_hash, "v6 session table",
- 200000 /* $$$$ config parameter nbuckets */ ,
- (64 << 20) /*$$$ config parameter table size */ );
-
- clib_bihash_init_16_8 (&smm->v4_half_open_hash, "v4 half-open table",
- 200000 /* $$$$ config parameter nbuckets */ ,
- (64 << 20) /*$$$ config parameter table size */ );
- clib_bihash_init_48_8 (&smm->v6_half_open_hash, "v6 half-open table",
- 200000 /* $$$$ config parameter nbuckets */ ,
- (64 << 20) /*$$$ config parameter table size */ );
+ session_lookup_init ();
smm->is_enabled = 1;
@@ -1328,11 +852,7 @@ clib_error_t *
session_manager_main_init (vlib_main_t * vm)
{
session_manager_main_t *smm = &session_manager_main;
-
- smm->vlib_main = vm;
- smm->vnet_main = vnet_get_main ();
smm->is_enabled = 0;
-
return 0;
}
diff --git a/src/vnet/session/session.h b/src/vnet/session/session.h
index 6c6163260f8..bb22f100529 100644
--- a/src/vnet/session/session.h
+++ b/src/vnet/session/session.h
@@ -15,7 +15,9 @@
#ifndef __included_session_h__
#define __included_session_h__
-#include <vnet/session/transport.h>
+#include <vnet/session/stream_session.h>
+#include <vnet/session/session_lookup.h>
+#include <vnet/session/transport_interface.h>
#include <vlibmemory/unix_shared_memory_queue.h>
#include <vnet/session/session_debug.h>
#include <vnet/session/segment_manager.h>
@@ -66,37 +68,6 @@ typedef enum
SESSION_QUEUE_N_NEXT,
} session_queue_next_t;
-#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;
-
-
-session_type_t
-session_type_from_proto_and_ip (transport_proto_t proto, u8 is_ip4);
-
-/*
- * Application session state
- */
-typedef enum
-{
- SESSION_STATE_LISTENING,
- SESSION_STATE_CONNECTING,
- SESSION_STATE_ACCEPTING,
- SESSION_STATE_READY,
- SESSION_STATE_CLOSED,
- SESSION_STATE_N_STATES,
-} stream_session_state_t;
-
typedef struct
{
void *fp;
@@ -116,48 +87,6 @@ typedef CLIB_PACKED (struct {
}) session_fifo_event_t;
/* *INDENT-ON* */
-typedef struct _stream_session_t
-{
- /** fifo pointers. Once allocated, these do not move */
- svm_fifo_t *server_rx_fifo;
- svm_fifo_t *server_tx_fifo;
-
- /** Type */
- u8 session_type;
-
- /** State */
- u8 session_state;
-
- u8 thread_index;
-
- /** To avoid n**2 "one event per frame" check */
- u8 enqueue_epoch;
-
- /** Pad to a multiple of 8 octets */
- u8 align_pad[4];
-
- /** svm segment index where fifos were allocated */
- u32 svm_segment_index;
-
- /** Session index in per_thread pool */
- u32 session_index;
-
- /** Transport specific */
- u32 connection_index;
-
- /** Application specific */
- u32 pid;
-
- /** stream server pool index */
- u32 app_index;
-
- /** Parent listener session if the result of an accept */
- u32 listener_index;
-
- /** Opaque, pad to a 64-octet boundary */
- u64 opaque[2];
-} stream_session_t;
-
/* Forward definition */
typedef struct _session_manager_main session_manager_main_t;
@@ -174,14 +103,6 @@ u8 session_node_lookup_fifo_event (svm_fifo_t * f, session_fifo_event_t * e);
struct _session_manager_main
{
- /** Lookup tables for established sessions and listeners */
- clib_bihash_16_8_t v4_session_hash;
- clib_bihash_48_8_t v6_session_hash;
-
- /** Lookup tables for half-open sessions */
- clib_bihash_16_8_t v4_half_open_hash;
- clib_bihash_48_8_t v6_half_open_hash;
-
/** Per worker thread session pools */
stream_session_t **sessions;
@@ -224,10 +145,6 @@ struct _session_manager_main
/** Preallocate session config parameter */
u32 preallocated_sessions;
- /* Convenience */
- vlib_main_t *vlib_main;
- vnet_main_t *vnet_main;
-
#if SESSION_DBG
/**
* last event poll time by thread
@@ -250,60 +167,6 @@ vnet_get_session_manager_main ()
return &session_manager_main;
}
-/*
- * Stream session functions
- */
-
-stream_session_t *stream_session_lookup_listener4 (ip4_address_t * lcl,
- u16 lcl_port, u8 proto);
-stream_session_t *stream_session_lookup4 (ip4_address_t * lcl,
- ip4_address_t * rmt, u16 lcl_port,
- u16 rmt_port, u8 proto);
-stream_session_t *stream_session_lookup_listener6 (ip6_address_t * lcl,
- u16 lcl_port, u8 proto);
-stream_session_t *stream_session_lookup6 (ip6_address_t * lcl,
- ip6_address_t * rmt, u16 lcl_port,
- u16 rmt_port, u8 proto);
-transport_connection_t
- * stream_session_lookup_transport_wt4 (ip4_address_t * lcl,
- ip4_address_t * rmt, u16 lcl_port,
- u16 rmt_port, u8 proto,
- u32 thread_index);
-transport_connection_t *stream_session_lookup_transport4 (ip4_address_t * lcl,
- ip4_address_t * rmt,
- u16 lcl_port,
- u16 rmt_port,
- u8 proto);
-transport_connection_t *stream_session_lookup_transport_wt6 (ip6_address_t *
- lcl,
- ip6_address_t *
- rmt,
- u16 lcl_port,
- u16 rmt_port,
- u8 proto,
- u32
- thread_index);
-transport_connection_t *stream_session_lookup_transport6 (ip6_address_t * lcl,
- ip6_address_t * rmt,
- u16 lcl_port,
- u16 rmt_port,
- u8 proto);
-
-stream_session_t *stream_session_lookup_listener (ip46_address_t * lcl,
- u16 lcl_port, u8 proto);
-transport_connection_t
- * stream_session_lookup_half_open (transport_connection_t * tc);
-void stream_session_table_add_for_tc (transport_connection_t * tc, u64 value);
-int stream_session_table_del_for_tc (transport_connection_t * tc);
-
-always_inline stream_session_t *
-stream_session_get_tsi (u64 ti_and_si, u32 thread_index)
-{
- ASSERT ((u32) (ti_and_si >> 32) == thread_index);
- return pool_elt_at_index (session_manager_main.sessions[thread_index],
- ti_and_si & 0xFFFFFFFFULL);
-}
-
always_inline u8
stream_session_is_valid (u32 si, u8 thread_index)
{
@@ -445,9 +308,6 @@ send_session_connected_callback (u32 app_index, u32 api_context,
stream_session_t * s, u8 is_fail);
-void session_register_transport (u8 type, const transport_proto_vft_t * vft);
-transport_proto_vft_t *session_get_transport_vft (u8 type);
-
clib_error_t *vnet_session_enable_disable (vlib_main_t * vm, u8 is_en);
always_inline unix_shared_memory_queue_t *
@@ -510,6 +370,24 @@ listen_session_del (stream_session_t * s)
pool_put (session_manager_main.listen_sessions[s->session_type], s);
}
+always_inline stream_session_t *
+session_manager_get_listener (u8 type, u32 index)
+{
+ return pool_elt_at_index (session_manager_main.listen_sessions[type],
+ index);
+}
+
+always_inline void
+session_manager_set_transport_rx_fn (u8 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_lookup.c b/src/vnet/session/session_lookup.c
new file mode 100644
index 00000000000..b3862ee3920
--- /dev/null
+++ b/src/vnet/session/session_lookup.c
@@ -0,0 +1,620 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** Generate typed init functions for multiple hash table styles... */
+#include <vppinfra/bihash_16_8.h>
+#include <vppinfra/bihash_template.h>
+
+#include <vppinfra/bihash_template.c>
+
+#undef __included_bihash_template_h__
+
+#include <vppinfra/bihash_48_8.h>
+#include <vppinfra/bihash_template.h>
+
+#include <vppinfra/bihash_template.c>
+#include <vnet/session/session_lookup.h>
+#include <vnet/session/session.h>
+
+static session_lookup_t session_lookup;
+extern transport_proto_vft_t *tp_vfts;
+
+/* *INDENT-OFF* */
+/* 16 octets */
+typedef CLIB_PACKED (struct {
+ union
+ {
+ struct
+ {
+ ip4_address_t src;
+ ip4_address_t dst;
+ u16 src_port;
+ u16 dst_port;
+ /* align by making this 4 octets even though its a 1-bit field
+ * NOTE: avoid key overlap with other transports that use 5 tuples for
+ * session identification.
+ */
+ u32 proto;
+ };
+ u64 as_u64[2];
+ };
+}) v4_connection_key_t;
+
+typedef CLIB_PACKED (struct {
+ union
+ {
+ struct
+ {
+ /* 48 octets */
+ ip6_address_t src;
+ ip6_address_t dst;
+ u16 src_port;
+ u16 dst_port;
+ u32 proto;
+ u64 unused;
+ };
+ u64 as_u64[6];
+ };
+}) v6_connection_key_t;
+/* *INDENT-ON* */
+
+typedef clib_bihash_kv_16_8_t session_kv4_t;
+typedef clib_bihash_kv_48_8_t session_kv6_t;
+
+always_inline void
+make_v4_ss_kv (session_kv4_t * kv, ip4_address_t * lcl, ip4_address_t * rmt,
+ u16 lcl_port, u16 rmt_port, u8 proto)
+{
+ v4_connection_key_t *key = (v4_connection_key_t *) kv->key;
+
+ key->src.as_u32 = lcl->as_u32;
+ key->dst.as_u32 = rmt->as_u32;
+ key->src_port = lcl_port;
+ key->dst_port = rmt_port;
+ key->proto = proto;
+
+ kv->value = ~0ULL;
+}
+
+always_inline void
+make_v4_listener_kv (session_kv4_t * kv, ip4_address_t * lcl, u16 lcl_port,
+ u8 proto)
+{
+ v4_connection_key_t *key = (v4_connection_key_t *) kv->key;
+
+ key->src.as_u32 = lcl->as_u32;
+ key->dst.as_u32 = 0;
+ key->src_port = lcl_port;
+ key->dst_port = 0;
+ key->proto = proto;
+
+ kv->value = ~0ULL;
+}
+
+always_inline void
+make_v4_ss_kv_from_tc (session_kv4_t * kv, transport_connection_t * t)
+{
+ return make_v4_ss_kv (kv, &t->lcl_ip.ip4, &t->rmt_ip.ip4, t->lcl_port,
+ t->rmt_port, t->proto);
+}
+
+always_inline void
+make_v6_ss_kv (session_kv6_t * kv, ip6_address_t * lcl, ip6_address_t * rmt,
+ u16 lcl_port, u16 rmt_port, u8 proto)
+{
+ v6_connection_key_t *key = (v6_connection_key_t *) kv->key;
+
+ key->src.as_u64[0] = lcl->as_u64[0];
+ key->src.as_u64[1] = lcl->as_u64[1];
+ key->dst.as_u64[0] = rmt->as_u64[0];
+ key->dst.as_u64[1] = rmt->as_u64[1];
+ key->src_port = lcl_port;
+ key->dst_port = rmt_port;
+ key->proto = proto;
+ key->unused = 0;
+
+ kv->value = ~0ULL;
+}
+
+always_inline void
+make_v6_listener_kv (session_kv6_t * kv, ip6_address_t * lcl, u16 lcl_port,
+ u8 proto)
+{
+ v6_connection_key_t *key = (v6_connection_key_t *) kv->key;
+
+ key->src.as_u64[0] = lcl->as_u64[0];
+ key->src.as_u64[1] = lcl->as_u64[1];
+ key->dst.as_u64[0] = 0;
+ key->dst.as_u64[1] = 0;
+ key->src_port = lcl_port;
+ key->dst_port = 0;
+ key->proto = proto;
+ key->unused = 0;
+
+ kv->value = ~0ULL;
+}
+
+always_inline void
+make_v6_ss_kv_from_tc (session_kv6_t * kv, transport_connection_t * t)
+{
+ make_v6_ss_kv (kv, &t->lcl_ip.ip6, &t->rmt_ip.ip6, t->lcl_port,
+ t->rmt_port, t->proto);
+}
+
+/*
+ * Session lookup key; (src-ip, dst-ip, src-port, dst-port, session-type)
+ * Value: (owner thread index << 32 | session_index);
+ */
+void
+stream_session_table_add_for_tc (transport_connection_t * tc, u64 value)
+{
+ session_lookup_t *sl = &session_lookup;
+ session_kv4_t kv4;
+ session_kv6_t kv6;
+
+ switch (tc->proto)
+ {
+ case SESSION_TYPE_IP4_UDP:
+ case SESSION_TYPE_IP4_TCP:
+ make_v4_ss_kv_from_tc (&kv4, tc);
+ kv4.value = value;
+ clib_bihash_add_del_16_8 (&sl->v4_session_hash, &kv4, 1 /* is_add */ );
+ break;
+ case SESSION_TYPE_IP6_UDP:
+ case SESSION_TYPE_IP6_TCP:
+ make_v6_ss_kv_from_tc (&kv6, tc);
+ kv6.value = value;
+ clib_bihash_add_del_48_8 (&sl->v6_session_hash, &kv6, 1 /* is_add */ );
+ break;
+ default:
+ clib_warning ("Session type not supported");
+ ASSERT (0);
+ }
+}
+
+void
+stream_session_table_add (session_manager_main_t * smm, stream_session_t * s,
+ u64 value)
+{
+ transport_connection_t *tc;
+
+ tc = tp_vfts[s->session_type].get_connection (s->connection_index,
+ s->thread_index);
+ stream_session_table_add_for_tc (tc, value);
+}
+
+void
+stream_session_half_open_table_add (session_type_t sst,
+ transport_connection_t * tc, u64 value)
+{
+ session_lookup_t *sl = &session_lookup;
+ session_kv4_t kv4;
+ session_kv6_t kv6;
+
+ switch (sst)
+ {
+ case SESSION_TYPE_IP4_UDP:
+ case SESSION_TYPE_IP4_TCP:
+ make_v4_ss_kv_from_tc (&kv4, tc);
+ kv4.value = value;
+ clib_bihash_add_del_16_8 (&sl->v4_half_open_hash, &kv4,
+ 1 /* is_add */ );
+ break;
+ case SESSION_TYPE_IP6_UDP:
+ case SESSION_TYPE_IP6_TCP:
+ make_v6_ss_kv_from_tc (&kv6, tc);
+ kv6.value = value;
+ clib_bihash_add_del_48_8 (&sl->v6_half_open_hash, &kv6,
+ 1 /* is_add */ );
+ break;
+ default:
+ clib_warning ("Session type not supported");
+ ASSERT (0);
+ }
+}
+
+int
+stream_session_table_del_for_tc (transport_connection_t * tc)
+{
+ session_lookup_t *sl = &session_lookup;
+ session_kv4_t kv4;
+ session_kv6_t kv6;
+ switch (tc->proto)
+ {
+ case SESSION_TYPE_IP4_UDP:
+ case SESSION_TYPE_IP4_TCP:
+ make_v4_ss_kv_from_tc (&kv4, tc);
+ return clib_bihash_add_del_16_8 (&sl->v4_session_hash, &kv4,
+ 0 /* is_add */ );
+ break;
+ case SESSION_TYPE_IP6_UDP:
+ case SESSION_TYPE_IP6_TCP:
+ make_v6_ss_kv_from_tc (&kv6, tc);
+ return clib_bihash_add_del_48_8 (&sl->v6_session_hash, &kv6,
+ 0 /* is_add */ );
+ break;
+ default:
+ clib_warning ("Session type not supported");
+ ASSERT (0);
+ }
+
+ return 0;
+}
+
+int
+stream_session_table_del (stream_session_t * s)
+{
+ transport_connection_t *ts;
+ ts = tp_vfts[s->session_type].get_connection (s->connection_index,
+ s->thread_index);
+ return stream_session_table_del_for_tc (ts);
+}
+
+void
+stream_session_half_open_table_del (u8 sst, transport_connection_t * tc)
+{
+ session_lookup_t *sl = &session_lookup;
+ session_kv4_t kv4;
+ session_kv6_t kv6;
+
+ switch (sst)
+ {
+ case SESSION_TYPE_IP4_UDP:
+ case SESSION_TYPE_IP4_TCP:
+ make_v4_ss_kv_from_tc (&kv4, tc);
+ clib_bihash_add_del_16_8 (&sl->v4_half_open_hash, &kv4,
+ 0 /* is_add */ );
+ break;
+ case SESSION_TYPE_IP6_UDP:
+ case SESSION_TYPE_IP6_TCP:
+ make_v6_ss_kv_from_tc (&kv6, tc);
+ clib_bihash_add_del_48_8 (&sl->v6_half_open_hash, &kv6,
+ 0 /* is_add */ );
+ break;
+ default:
+ clib_warning ("Session type not supported");
+ ASSERT (0);
+ }
+}
+
+stream_session_t *
+stream_session_lookup_listener4 (ip4_address_t * lcl, u16 lcl_port, u8 proto)
+{
+ session_lookup_t *sl = &session_lookup;
+ session_kv4_t kv4;
+ int rv;
+
+ make_v4_listener_kv (&kv4, lcl, lcl_port, proto);
+ rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
+ if (rv == 0)
+ return session_manager_get_listener (proto, (u32) kv4.value);
+
+ /* Zero out the lcl ip */
+ kv4.key[0] = 0;
+ rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
+ if (rv == 0)
+ return session_manager_get_listener (proto, (u32) kv4.value);
+
+ return 0;
+}
+
+/** Looks up a session based on the 5-tuple passed as argument.
+ *
+ * First it tries to find an established session, if this fails, it tries
+ * finding a listener session if this fails, it tries a lookup with a
+ * wildcarded local source (listener bound to all interfaces)
+ */
+stream_session_t *
+stream_session_lookup4 (ip4_address_t * lcl, ip4_address_t * rmt,
+ u16 lcl_port, u16 rmt_port, u8 proto)
+{
+ session_lookup_t *sl = &session_lookup;
+ session_kv4_t kv4;
+ stream_session_t *s;
+ int rv;
+
+ /* Lookup session amongst established ones */
+ make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
+ rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
+ if (rv == 0)
+ return stream_session_get_from_handle (kv4.value);
+
+ /* If nothing is found, check if any listener is available */
+ if ((s = stream_session_lookup_listener4 (lcl, lcl_port, proto)))
+ return s;
+
+ /* Finally, try half-open connections */
+ rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
+ if (rv == 0)
+ return stream_session_get_from_handle (kv4.value);
+ return 0;
+}
+
+stream_session_t *
+stream_session_lookup_listener6 (ip6_address_t * lcl, u16 lcl_port, u8 proto)
+{
+ session_lookup_t *sl = &session_lookup;
+ session_kv6_t kv6;
+ int rv;
+
+ make_v6_listener_kv (&kv6, lcl, lcl_port, proto);
+ rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
+ if (rv == 0)
+ return session_manager_get_listener (proto, (u32) kv6.value);
+
+ /* Zero out the lcl ip */
+ kv6.key[0] = kv6.key[1] = 0;
+ rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
+ if (rv == 0)
+ return session_manager_get_listener (proto, (u32) kv6.value);
+
+ return 0;
+}
+
+/* Looks up a session based on the 5-tuple passed as argument.
+ * First it tries to find an established session, if this fails, it tries
+ * finding a listener session if this fails, it tries a lookup with a
+ * wildcarded local source (listener bound to all interfaces) */
+stream_session_t *
+stream_session_lookup6 (ip6_address_t * lcl, ip6_address_t * rmt,
+ u16 lcl_port, u16 rmt_port, u8 proto)
+{
+ session_lookup_t *sl = &session_lookup;
+ session_kv6_t kv6;
+ stream_session_t *s;
+ int rv;
+
+ make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
+ rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
+ if (rv == 0)
+ return stream_session_get_from_handle (kv6.value);
+
+ /* If nothing is found, check if any listener is available */
+ if ((s = stream_session_lookup_listener6 (lcl, lcl_port, proto)))
+ return s;
+
+ /* Finally, try half-open connections */
+ rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
+ if (rv == 0)
+ return stream_session_get_from_handle (kv6.value);
+ return 0;
+}
+
+stream_session_t *
+stream_session_lookup_listener (ip46_address_t * lcl, u16 lcl_port, u8 proto)
+{
+ switch (proto)
+ {
+ case SESSION_TYPE_IP4_UDP:
+ case SESSION_TYPE_IP4_TCP:
+ return stream_session_lookup_listener4 (&lcl->ip4, lcl_port, proto);
+ break;
+ case SESSION_TYPE_IP6_UDP:
+ case SESSION_TYPE_IP6_TCP:
+ return stream_session_lookup_listener6 (&lcl->ip6, lcl_port, proto);
+ break;
+ }
+ return 0;
+}
+
+u64
+stream_session_half_open_lookup_handle (ip46_address_t * lcl,
+ ip46_address_t * rmt, u16 lcl_port,
+ u16 rmt_port, u8 proto)
+{
+ session_lookup_t *sl = &session_lookup;
+ session_kv4_t kv4;
+ session_kv6_t kv6;
+ int rv;
+
+ switch (proto)
+ {
+ case SESSION_TYPE_IP4_UDP:
+ case SESSION_TYPE_IP4_TCP:
+ make_v4_ss_kv (&kv4, &lcl->ip4, &rmt->ip4, lcl_port, rmt_port, proto);
+ rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
+
+ if (rv == 0)
+ return kv4.value;
+
+ return HALF_OPEN_LOOKUP_INVALID_VALUE;
+ break;
+ case SESSION_TYPE_IP6_UDP:
+ case SESSION_TYPE_IP6_TCP:
+ make_v6_ss_kv (&kv6, &lcl->ip6, &rmt->ip6, lcl_port, rmt_port, proto);
+ rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
+
+ if (rv == 0)
+ return kv6.value;
+
+ return HALF_OPEN_LOOKUP_INVALID_VALUE;
+ break;
+ }
+ return HALF_OPEN_LOOKUP_INVALID_VALUE;
+}
+
+transport_connection_t *
+stream_session_half_open_lookup (ip46_address_t * lcl, ip46_address_t * rmt,
+ u16 lcl_port, u16 rmt_port, u8 proto)
+{
+ u64 handle;
+ handle =
+ stream_session_half_open_lookup_handle (lcl, rmt, lcl_port, rmt_port,
+ proto);
+ if (handle != HALF_OPEN_LOOKUP_INVALID_VALUE)
+ return tp_vfts[proto].get_half_open (handle & 0xFFFFFFFF);
+ return 0;
+}
+
+always_inline stream_session_t *
+stream_session_get_tsi (u64 ti_and_si, u32 thread_index)
+{
+ ASSERT ((u32) (ti_and_si >> 32) == thread_index);
+ return pool_elt_at_index (session_manager_main.sessions[thread_index],
+ ti_and_si & 0xFFFFFFFFULL);
+}
+
+transport_connection_t *
+stream_session_lookup_transport_wt4 (ip4_address_t * lcl, ip4_address_t * rmt,
+ u16 lcl_port, u16 rmt_port, u8 proto,
+ u32 my_thread_index)
+{
+ session_lookup_t *sl = &session_lookup;
+ session_kv4_t kv4;
+ stream_session_t *s;
+ int rv;
+
+ /* Lookup session amongst established ones */
+ make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
+ rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
+ if (rv == 0)
+ {
+ s = stream_session_get_tsi (kv4.value, my_thread_index);
+ return tp_vfts[s->session_type].get_connection (s->connection_index,
+ my_thread_index);
+ }
+
+ /* If nothing is found, check if any listener is available */
+ s = stream_session_lookup_listener4 (lcl, lcl_port, proto);
+ if (s)
+ return tp_vfts[s->session_type].get_listener (s->connection_index);
+
+ /* Finally, try half-open connections */
+ rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
+ if (rv == 0)
+ return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF);
+ return 0;
+}
+
+transport_connection_t *
+stream_session_lookup_transport4 (ip4_address_t * lcl, ip4_address_t * rmt,
+ u16 lcl_port, u16 rmt_port, u8 proto)
+{
+ session_lookup_t *sl = &session_lookup;
+ session_kv4_t kv4;
+ stream_session_t *s;
+ int rv;
+
+ /* Lookup session amongst established ones */
+ make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
+ rv = clib_bihash_search_inline_16_8 (&sl->v4_session_hash, &kv4);
+ if (rv == 0)
+ {
+ s = stream_session_get_from_handle (kv4.value);
+ return tp_vfts[s->session_type].get_connection (s->connection_index,
+ s->thread_index);
+ }
+
+ /* If nothing is found, check if any listener is available */
+ s = stream_session_lookup_listener4 (lcl, lcl_port, proto);
+ if (s)
+ return tp_vfts[s->session_type].get_listener (s->connection_index);
+
+ /* Finally, try half-open connections */
+ rv = clib_bihash_search_inline_16_8 (&sl->v4_half_open_hash, &kv4);
+ if (rv == 0)
+ return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF);
+ return 0;
+}
+
+transport_connection_t *
+stream_session_lookup_transport_wt6 (ip6_address_t * lcl, ip6_address_t * rmt,
+ u16 lcl_port, u16 rmt_port, u8 proto,
+ u32 my_thread_index)
+{
+ session_lookup_t *sl = &session_lookup;
+ stream_session_t *s;
+ session_kv6_t kv6;
+ int rv;
+
+ make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
+ rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
+ if (rv == 0)
+ {
+ s = stream_session_get_tsi (kv6.value, my_thread_index);
+ return tp_vfts[s->session_type].get_connection (s->connection_index,
+ my_thread_index);
+ }
+
+ /* If nothing is found, check if any listener is available */
+ s = stream_session_lookup_listener6 (lcl, lcl_port, proto);
+ if (s)
+ return tp_vfts[s->session_type].get_listener (s->connection_index);
+
+ /* Finally, try half-open connections */
+ rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
+ if (rv == 0)
+ return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF);
+
+ return 0;
+}
+
+transport_connection_t *
+stream_session_lookup_transport6 (ip6_address_t * lcl, ip6_address_t * rmt,
+ u16 lcl_port, u16 rmt_port, u8 proto)
+{
+ session_lookup_t *sl = &session_lookup;
+ stream_session_t *s;
+ session_kv6_t kv6;
+ int rv;
+
+ make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
+ rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
+ if (rv == 0)
+ {
+ s = stream_session_get_from_handle (kv6.value);
+ return tp_vfts[s->session_type].get_connection (s->connection_index,
+ s->thread_index);
+ }
+
+ /* If nothing is found, check if any listener is available */
+ s = stream_session_lookup_listener6 (lcl, lcl_port, proto);
+ if (s)
+ return tp_vfts[s->session_type].get_listener (s->connection_index);
+
+ /* Finally, try half-open connections */
+ rv = clib_bihash_search_inline_48_8 (&sl->v6_half_open_hash, &kv6);
+ if (rv == 0)
+ return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF);
+
+ return 0;
+}
+
+void
+session_lookup_init (void)
+{
+ session_lookup_t *sl = &session_lookup;
+ clib_bihash_init_16_8 (&sl->v4_session_hash, "v4 session table",
+ 200000 /* $$$$ config parameter nbuckets */ ,
+ (64 << 20) /*$$$ config parameter table size */ );
+ clib_bihash_init_48_8 (&sl->v6_session_hash, "v6 session table",
+ 200000 /* $$$$ config parameter nbuckets */ ,
+ (64 << 20) /*$$$ config parameter table size */ );
+
+ clib_bihash_init_16_8 (&sl->v4_half_open_hash, "v4 half-open table",
+ 200000 /* $$$$ config parameter nbuckets */ ,
+ (64 << 20) /*$$$ config parameter table size */ );
+ clib_bihash_init_48_8 (&sl->v6_half_open_hash, "v6 half-open table",
+ 200000 /* $$$$ config parameter nbuckets */ ,
+ (64 << 20) /*$$$ config parameter table size */ );
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/session/session_lookup.h b/src/vnet/session/session_lookup.h
new file mode 100644
index 00000000000..9e92dab1b1d
--- /dev/null
+++ b/src/vnet/session/session_lookup.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_VNET_SESSION_SESSION_LOOKUP_H_
+#define SRC_VNET_SESSION_SESSION_LOOKUP_H_
+
+#include <vnet/session/stream_session.h>
+#include <vnet/session/transport.h>
+
+typedef struct _session_lookup
+{
+ /** Lookup tables for established sessions and listeners */
+ clib_bihash_16_8_t v4_session_hash;
+ clib_bihash_48_8_t v6_session_hash;
+
+ /** Lookup tables for half-open sessions */
+ clib_bihash_16_8_t v4_half_open_hash;
+ clib_bihash_48_8_t v6_half_open_hash;
+} session_lookup_t;
+
+stream_session_t *stream_session_lookup_listener4 (ip4_address_t * lcl,
+ u16 lcl_port, u8 proto);
+stream_session_t *stream_session_lookup4 (ip4_address_t * lcl,
+ ip4_address_t * rmt, u16 lcl_port,
+ u16 rmt_port, u8 proto);
+stream_session_t *stream_session_lookup_listener6 (ip6_address_t * lcl,
+ u16 lcl_port, u8 proto);
+stream_session_t *stream_session_lookup6 (ip6_address_t * lcl,
+ ip6_address_t * rmt, u16 lcl_port,
+ u16 rmt_port, u8 proto);
+transport_connection_t *stream_session_lookup_transport_wt4 (ip4_address_t *
+ lcl,
+ ip4_address_t *
+ rmt,
+ u16 lcl_port,
+ u16 rmt_port,
+ u8 proto,
+ u32
+ thread_index);
+transport_connection_t *stream_session_lookup_transport4 (ip4_address_t * lcl,
+ ip4_address_t * rmt,
+ u16 lcl_port,
+ u16 rmt_port,
+ u8 proto);
+transport_connection_t *stream_session_lookup_transport_wt6 (ip6_address_t *
+ lcl,
+ ip6_address_t *
+ rmt,
+ u16 lcl_port,
+ u16 rmt_port,
+ u8 proto,
+ u32
+ thread_index);
+transport_connection_t *stream_session_lookup_transport6 (ip6_address_t * lcl,
+ ip6_address_t * rmt,
+ u16 lcl_port,
+ u16 rmt_port,
+ u8 proto);
+
+stream_session_t *stream_session_lookup_listener (ip46_address_t * lcl,
+ u16 lcl_port, u8 proto);
+u64 stream_session_half_open_lookup_handle (ip46_address_t * lcl,
+ ip46_address_t * rmt,
+ u16 lcl_port,
+ u16 rmt_port, u8 proto);
+transport_connection_t *stream_session_half_open_lookup (ip46_address_t * lcl,
+ ip46_address_t * rmt,
+ u16 lcl_port,
+ u16 rmt_port,
+ u8 proto);
+void stream_session_table_add_for_tc (transport_connection_t * tc, u64 value);
+int stream_session_table_del_for_tc (transport_connection_t * tc);
+int stream_session_table_del (stream_session_t * s);
+void stream_session_half_open_table_del (u8 sst, transport_connection_t * tc);
+void stream_session_half_open_table_add (session_type_t sst,
+ transport_connection_t * tc,
+ u64 value);
+
+void session_lookup_init (void);
+
+#endif /* SRC_VNET_SESSION_SESSION_LOOKUP_H_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/session/node.c b/src/vnet/session/session_node.c
index 8d703b0b302..8d703b0b302 100644
--- a/src/vnet/session/node.c
+++ b/src/vnet/session/session_node.c
diff --git a/src/vnet/session/stream_session.h b/src/vnet/session/stream_session.h
new file mode 100644
index 00000000000..82bbf521ce9
--- /dev/null
+++ b/src/vnet/session/stream_session.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_VNET_SESSION_STREAM_SESSION_H_
+#define SRC_VNET_SESSION_STREAM_SESSION_H_
+
+#include <vnet/vnet.h>
+#include <svm/svm_fifo.h>
+
+#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;
+
+/*
+ * Application session state
+ */
+typedef enum
+{
+ SESSION_STATE_LISTENING,
+ SESSION_STATE_CONNECTING,
+ SESSION_STATE_ACCEPTING,
+ SESSION_STATE_READY,
+ SESSION_STATE_CLOSED,
+ SESSION_STATE_N_STATES,
+} stream_session_state_t;
+
+typedef struct _stream_session_t
+{
+ /** fifo pointers. Once allocated, these do not move */
+ svm_fifo_t *server_rx_fifo;
+ svm_fifo_t *server_tx_fifo;
+
+ /** Type */
+ u8 session_type;
+
+ /** State */
+ u8 session_state;
+
+ u8 thread_index;
+
+ /** To avoid n**2 "one event per frame" check */
+ u8 enqueue_epoch;
+
+ /** Pad to a multiple of 8 octets */
+ u8 align_pad[4];
+
+ /** svm segment index where fifos were allocated */
+ u32 svm_segment_index;
+
+ /** Session index in per_thread pool */
+ u32 session_index;
+
+ /** Transport specific */
+ u32 connection_index;
+
+ /** stream server pool index */
+ u32 app_index;
+
+ /** Parent listener session if the result of an accept */
+ u32 listener_index;
+
+ u32 opaque2;
+
+ /** Opaque, pad to a 64-octet boundary */
+ u64 opaque[2];
+} stream_session_t;
+
+#endif /* SRC_VNET_SESSION_STREAM_SESSION_H_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/session/transport.c b/src/vnet/session/transport.c
deleted file mode 100644
index abd94ba4f1d..00000000000
--- a/src/vnet/session/transport.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2017 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <vnet/session/transport.h>
-
-u32
-transport_endpoint_lookup (transport_endpoint_table_t *ht, ip46_address_t *ip,
- u16 port)
-{
- clib_bihash_kv_24_8_t kv;
- int rv;
-
- kv.key[0] = ip->as_u64[0];
- kv.key[1] = ip->as_u64[1];
- kv.key[2] = port;
-
- rv = clib_bihash_search_inline_24_8 (ht, &kv);
- if (rv == 0)
- return kv.value;
-
- return TRANSPORT_ENDPOINT_INVALID_INDEX;
-}
-
-void
-transport_endpoint_table_add (transport_endpoint_table_t *ht,
- transport_endpoint_t *te, u32 value)
-{
- clib_bihash_kv_24_8_t kv;
-
- kv.key[0] = te->ip.as_u64[0];
- kv.key[1] = te->ip.as_u64[1];
- kv.key[2] = te->port;
- kv.value = value;
-
- clib_bihash_add_del_24_8 (ht, &kv, 1);
-}
-
-void
-transport_endpoint_table_del (transport_endpoint_table_t *ht,
- transport_endpoint_t *te)
-{
- clib_bihash_kv_24_8_t kv;
-
- kv.key[0] = te->ip.as_u64[0];
- kv.key[1] = te->ip.as_u64[1];
- kv.key[2] = te->port;
-
- clib_bihash_add_del_24_8 (ht, &kv, 0);
-}
-
-
-
diff --git a/src/vnet/session/transport.h b/src/vnet/session/transport.h
index 9c38bab9c4f..3895a60af48 100644
--- a/src/vnet/session/transport.h
+++ b/src/vnet/session/transport.h
@@ -21,6 +21,7 @@
#include <vppinfra/bihash_16_8.h>
#include <vppinfra/bihash_48_8.h>
#include <vnet/tcp/tcp_debug.h>
+
/*
* Protocol independent transport properties associated to a session
*/
@@ -31,6 +32,7 @@ typedef struct _transport_connection
u16 lcl_port; /**< Local port */
u16 rmt_port; /**< Remote port */
u8 proto; /**< Protocol id (also session type) */
+ u32 vrf; /**< FIB table id */
u32 s_index; /**< Parent session index */
u32 c_index; /**< Connection index in transport pool */
@@ -55,6 +57,7 @@ typedef struct _transport_connection
#define c_lcl_port connection.lcl_port
#define c_rmt_port connection.rmt_port
#define c_proto connection.proto
+#define c_vrf connection.vrf
#define c_state connection.state
#define c_s_index connection.s_index
#define c_c_index connection.c_index
@@ -66,165 +69,6 @@ typedef struct _transport_connection
#define c_rmt_dpo connection.rmt_dpo
} transport_connection_t;
-/*
- * Transport protocol virtual function table
- */
-typedef struct _transport_proto_vft
-{
- /*
- * Setup
- */
- u32 (*bind) (u32, ip46_address_t *, u16);
- u32 (*unbind) (u32);
- int (*open) (ip46_address_t * addr, u16 port_host_byte_order);
- void (*close) (u32 conn_index, u32 thread_index);
- void (*cleanup) (u32 conn_index, u32 thread_index);
-
- /*
- * Transmission
- */
- u32 (*push_header) (transport_connection_t * tconn, vlib_buffer_t * b);
- u16 (*send_mss) (transport_connection_t * tc);
- u32 (*send_space) (transport_connection_t * tc);
- u32 (*tx_fifo_offset) (transport_connection_t * tc);
-
- /*
- * Connection retrieval
- */
- transport_connection_t *(*get_connection) (u32 conn_idx, u32 thread_idx);
- transport_connection_t *(*get_listener) (u32 conn_index);
- transport_connection_t *(*get_half_open) (u32 conn_index);
-
- /*
- * Format
- */
- u8 *(*format_connection) (u8 * s, va_list * args);
- u8 *(*format_listener) (u8 * s, va_list * args);
- u8 *(*format_half_open) (u8 * s, va_list * args);
-} transport_proto_vft_t;
-
-/* *INDENT-OFF* */
-/* 16 octets */
-typedef CLIB_PACKED (struct {
- union
- {
- struct
- {
- ip4_address_t src;
- ip4_address_t dst;
- u16 src_port;
- u16 dst_port;
- /* align by making this 4 octets even though its a 1-bit field
- * NOTE: avoid key overlap with other transports that use 5 tuples for
- * session identification.
- */
- u32 proto;
- };
- u64 as_u64[2];
- };
-}) v4_connection_key_t;
-
-typedef CLIB_PACKED (struct {
- union
- {
- struct
- {
- /* 48 octets */
- ip6_address_t src;
- ip6_address_t dst;
- u16 src_port;
- u16 dst_port;
- u32 proto;
- u64 unused;
- };
- u64 as_u64[6];
- };
-}) v6_connection_key_t;
-/* *INDENT-ON* */
-
-typedef clib_bihash_kv_16_8_t session_kv4_t;
-typedef clib_bihash_kv_48_8_t session_kv6_t;
-
-always_inline void
-make_v4_ss_kv (session_kv4_t * kv, ip4_address_t * lcl, ip4_address_t * rmt,
- u16 lcl_port, u16 rmt_port, u8 proto)
-{
- v4_connection_key_t *key = (v4_connection_key_t *) kv->key;
-
- key->src.as_u32 = lcl->as_u32;
- key->dst.as_u32 = rmt->as_u32;
- key->src_port = lcl_port;
- key->dst_port = rmt_port;
- key->proto = proto;
-
- kv->value = ~0ULL;
-}
-
-always_inline void
-make_v4_listener_kv (session_kv4_t * kv, ip4_address_t * lcl, u16 lcl_port,
- u8 proto)
-{
- v4_connection_key_t *key = (v4_connection_key_t *) kv->key;
-
- key->src.as_u32 = lcl->as_u32;
- key->dst.as_u32 = 0;
- key->src_port = lcl_port;
- key->dst_port = 0;
- key->proto = proto;
-
- kv->value = ~0ULL;
-}
-
-always_inline void
-make_v4_ss_kv_from_tc (session_kv4_t * kv, transport_connection_t * t)
-{
- return make_v4_ss_kv (kv, &t->lcl_ip.ip4, &t->rmt_ip.ip4, t->lcl_port,
- t->rmt_port, t->proto);
-}
-
-always_inline void
-make_v6_ss_kv (session_kv6_t * kv, ip6_address_t * lcl, ip6_address_t * rmt,
- u16 lcl_port, u16 rmt_port, u8 proto)
-{
- v6_connection_key_t *key = (v6_connection_key_t *) kv->key;
-
- key->src.as_u64[0] = lcl->as_u64[0];
- key->src.as_u64[1] = lcl->as_u64[1];
- key->dst.as_u64[0] = rmt->as_u64[0];
- key->dst.as_u64[1] = rmt->as_u64[1];
- key->src_port = lcl_port;
- key->dst_port = rmt_port;
- key->proto = proto;
- key->unused = 0;
-
- kv->value = ~0ULL;
-}
-
-always_inline void
-make_v6_listener_kv (session_kv6_t * kv, ip6_address_t * lcl, u16 lcl_port,
- u8 proto)
-{
- v6_connection_key_t *key = (v6_connection_key_t *) kv->key;
-
- key->src.as_u64[0] = lcl->as_u64[0];
- key->src.as_u64[1] = lcl->as_u64[1];
- key->dst.as_u64[0] = 0;
- key->dst.as_u64[1] = 0;
- key->src_port = lcl_port;
- key->dst_port = 0;
- key->proto = proto;
- key->unused = 0;
-
- kv->value = ~0ULL;
-}
-
-always_inline void
-make_v6_ss_kv_from_tc (session_kv6_t * kv, transport_connection_t * t)
-{
- make_v6_ss_kv (kv, &t->lcl_ip.ip6, &t->rmt_ip.ip6, t->lcl_port,
- t->rmt_port, t->proto);
-}
-
typedef enum _transport_proto
{
TRANSPORT_PROTO_TCP,
@@ -239,18 +83,6 @@ typedef struct _transport_endpoint
u32 vrf; /** fib table the endpoint is associated with */
} transport_endpoint_t;
-typedef clib_bihash_24_8_t transport_endpoint_table_t;
-
-#define TRANSPORT_ENDPOINT_INVALID_INDEX ((u32)~0)
-
-u32
-transport_endpoint_lookup (transport_endpoint_table_t * ht,
- ip46_address_t * ip, u16 port);
-void transport_endpoint_table_add (transport_endpoint_table_t * ht,
- transport_endpoint_t * te, u32 value);
-void transport_endpoint_table_del (transport_endpoint_table_t * ht,
- transport_endpoint_t * te);
-
#endif /* VNET_VNET_URI_TRANSPORT_H_ */
/*
diff --git a/src/vnet/session/transport_interface.c b/src/vnet/session/transport_interface.c
new file mode 100644
index 00000000000..eb12aa69475
--- /dev/null
+++ b/src/vnet/session/transport_interface.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/session/transport_interface.h>
+#include <vnet/session/session.h>
+
+/**
+ * Per-type vector of transport protocol virtual function tables
+ */
+transport_proto_vft_t *tp_vfts;
+
+u32
+transport_endpoint_lookup (transport_endpoint_table_t * ht,
+ ip46_address_t * ip, u16 port)
+{
+ clib_bihash_kv_24_8_t kv;
+ int rv;
+
+ kv.key[0] = ip->as_u64[0];
+ kv.key[1] = ip->as_u64[1];
+ kv.key[2] = port;
+
+ rv = clib_bihash_search_inline_24_8 (ht, &kv);
+ if (rv == 0)
+ return kv.value;
+
+ return TRANSPORT_ENDPOINT_INVALID_INDEX;
+}
+
+void
+transport_endpoint_table_add (transport_endpoint_table_t * ht,
+ transport_endpoint_t * te, u32 value)
+{
+ clib_bihash_kv_24_8_t kv;
+
+ kv.key[0] = te->ip.as_u64[0];
+ kv.key[1] = te->ip.as_u64[1];
+ kv.key[2] = te->port;
+ kv.value = value;
+
+ clib_bihash_add_del_24_8 (ht, &kv, 1);
+}
+
+void
+transport_endpoint_table_del (transport_endpoint_table_t * ht,
+ transport_endpoint_t * te)
+{
+ clib_bihash_kv_24_8_t kv;
+
+ kv.key[0] = te->ip.as_u64[0];
+ kv.key[1] = te->ip.as_u64[1];
+ kv.key[2] = te->port;
+
+ clib_bihash_add_del_24_8 (ht, &kv, 0);
+}
+
+/**
+ * Register transport virtual function table.
+ *
+ * @param type - session type (not protocol type)
+ * @param vft - virtual function table
+ */
+void
+session_register_transport (u8 session_type,
+ const transport_proto_vft_t * vft)
+{
+ vec_validate (tp_vfts, session_type);
+ tp_vfts[session_type] = *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);
+}
+
+/**
+ * Get transport virtual function table
+ *
+ * @param type - session type (not protocol type)
+ */
+transport_proto_vft_t *
+session_get_transport_vft (u8 session_type)
+{
+ if (session_type >= vec_len (tp_vfts))
+ return 0;
+ return &tp_vfts[session_type];
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/session/transport_interface.h b/src/vnet/session/transport_interface.h
new file mode 100644
index 00000000000..b7e86ee7960
--- /dev/null
+++ b/src/vnet/session/transport_interface.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_VNET_SESSION_TRANSPORT_INTERFACE_H_
+#define SRC_VNET_SESSION_TRANSPORT_INTERFACE_H_
+
+#include <vnet/vnet.h>
+#include <vnet/session/transport.h>
+
+/*
+ * Transport protocol virtual function table
+ */
+typedef struct _transport_proto_vft
+{
+ /*
+ * Setup
+ */
+ u32 (*bind) (u32 session_index, transport_endpoint_t * lcl);
+ u32 (*unbind) (u32);
+ int (*open) (transport_endpoint_t * rmt);
+ void (*close) (u32 conn_index, u32 thread_index);
+ void (*cleanup) (u32 conn_index, u32 thread_index);
+
+ /*
+ * Transmission
+ */
+ u32 (*push_header) (transport_connection_t * tconn, vlib_buffer_t * b);
+ u16 (*send_mss) (transport_connection_t * tc);
+ u32 (*send_space) (transport_connection_t * tc);
+ u32 (*tx_fifo_offset) (transport_connection_t * tc);
+
+ /*
+ * Connection retrieval
+ */
+ transport_connection_t *(*get_connection) (u32 conn_idx, u32 thread_idx);
+ transport_connection_t *(*get_listener) (u32 conn_index);
+ transport_connection_t *(*get_half_open) (u32 conn_index);
+
+ /*
+ * Format
+ */
+ u8 *(*format_connection) (u8 * s, va_list * args);
+ u8 *(*format_listener) (u8 * s, va_list * args);
+ u8 *(*format_half_open) (u8 * s, va_list * args);
+} transport_proto_vft_t;
+
+typedef clib_bihash_24_8_t transport_endpoint_table_t;
+
+#define TRANSPORT_ENDPOINT_INVALID_INDEX ((u32)~0)
+
+u32 transport_endpoint_lookup (transport_endpoint_table_t * ht,
+ ip46_address_t * ip, u16 port);
+void transport_endpoint_table_add (transport_endpoint_table_t * ht,
+ transport_endpoint_t * te, u32 value);
+void transport_endpoint_table_del (transport_endpoint_table_t * ht,
+ transport_endpoint_t * te);
+
+void session_register_transport (u8 session_type,
+ const transport_proto_vft_t * vft);
+transport_proto_vft_t *session_get_transport_vft (u8 session_type);
+
+#endif /* SRC_VNET_SESSION_TRANSPORT_INTERFACE_H_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */