summaryrefslogtreecommitdiffstats
path: root/src/vnet/session/session_lookup.c
diff options
context:
space:
mode:
authorFlorin Coras <fcoras@cisco.com>2017-10-02 00:18:51 -0700
committerDave Barach <openvpp@barachs.net>2017-10-10 20:42:50 +0000
commitcea194d8f973a2f2b5ef72d212533057174cc70a (patch)
tree6fdd2e8a929c62625d1ad35bfbec342129989aef /src/vnet/session/session_lookup.c
parent1f36a93d3d68f5ba6dcda08809394ce757cefd72 (diff)
session: add support for application namespacing
Applications are now provided the option to select the namespace they are to be attached to and the scope of their attachement. Application namespaces are meant to: 1) constrain the scope of communication through the network by association with source interfaces and/or fib tables that provide the source ips to be used and limit the scope of routing 2) provide a namespace local scope to session layer communication, as opposed to the global scope provided by 1). That is, sessions can be established without assistance from transport and network layers. Albeit, zero/local-host ip addresses must still be provided in session establishment messages due to existing application idiosyncrasies. This mode of communication uses shared-memory fifos (cut-through sessions) exclusively. If applications request no namespace, they are assigned to the default one, which at its turn uses the default fib. Applications can request access to both local and global scopes for a namespace. If no scope is specified, session layer defaults to the global one. When a sw_if_index is provided for a namespace, zero-ip (INADDR_ANY) binds are converted to binds to the requested interface. Change-Id: Ia0f660bbf7eec7f89673f75b4821fc7c3d58e3d1 Signed-off-by: Florin Coras <fcoras@cisco.com>
Diffstat (limited to 'src/vnet/session/session_lookup.c')
-rw-r--r--src/vnet/session/session_lookup.c859
1 files changed, 633 insertions, 226 deletions
diff --git a/src/vnet/session/session_lookup.c b/src/vnet/session/session_lookup.c
index 4487b1c305f..796d93ec33e 100644
--- a/src/vnet/session/session_lookup.c
+++ b/src/vnet/session/session_lookup.c
@@ -27,10 +27,19 @@
#include <vppinfra/bihash_template.c>
#include <vnet/session/session_lookup.h>
#include <vnet/session/session.h>
+#include <vnet/session/application.h>
-static session_lookup_t session_lookup;
+/**
+ * External vector of per transport virtual functions table
+ */
extern transport_proto_vft_t *tp_vfts;
+/**
+ * Network namespace index (i.e., fib index) to session lookup table. We
+ * should have one per network protocol type but for now we only support IP4/6
+ */
+static u32 *fib_index_to_table_index[2];
+
/* *INDENT-OFF* */
/* 16 octets */
typedef CLIB_PACKED (struct {
@@ -153,461 +162,859 @@ make_v6_ss_kv_from_tc (session_kv6_t * kv, transport_connection_t * t)
session_type_from_proto_and_ip (t->transport_proto, 0));
}
-/*
- * Session lookup key; (src-ip, dst-ip, src-port, dst-port, session-type)
- * Value: (owner thread index << 32 | session_index);
+
+static session_table_t *
+session_table_get_or_alloc_for_connection (transport_connection_t * tc)
+{
+ session_table_t *st;
+ u32 table_index, fib_proto = transport_connection_fib_proto (tc);
+ if (vec_len (fib_index_to_table_index[fib_proto]) <= tc->fib_index)
+ {
+ st = session_table_alloc ();
+ table_index = session_table_index (st);
+ vec_validate (fib_index_to_table_index[fib_proto], tc->fib_index);
+ fib_index_to_table_index[fib_proto][tc->fib_index] = table_index;
+ return st;
+ }
+ else
+ {
+ table_index = fib_index_to_table_index[fib_proto][tc->fib_index];
+ return session_table_get (table_index);
+ }
+}
+
+static session_table_t *
+session_table_get_for_connection (transport_connection_t * tc)
+{
+ u32 fib_proto = transport_connection_fib_proto (tc);
+ if (vec_len (fib_index_to_table_index[fib_proto]) <= tc->fib_index)
+ return 0;
+ return
+ session_table_get (fib_index_to_table_index[fib_proto][tc->fib_index]);
+}
+
+static session_table_t *
+session_table_get_for_fib_index (u32 fib_proto, u32 fib_index)
+{
+ if (vec_len (fib_index_to_table_index[fib_proto]) <= fib_index)
+ return 0;
+ return session_table_get (fib_index_to_table_index[fib_proto][fib_index]);
+}
+
+u32
+session_lookup_get_index_for_fib (u32 fib_proto, u32 fib_index)
+{
+ if (vec_len (fib_index_to_table_index[fib_proto]) <= fib_index)
+ return SESSION_TABLE_INVALID_INDEX;
+ return fib_index_to_table_index[fib_proto][fib_index];
+}
+
+/**
+ * Add transport connection to a session table
+ *
+ * Session lookup 5-tuple (src-ip, dst-ip, src-port, dst-port, session-type)
+ * is added to requested session table.
+ *
+ * @param tc transport connection to be added
+ * @param value value to be stored
+ *
+ * @return non-zero if failure
*/
-void
-stream_session_table_add_for_tc (transport_connection_t * tc, u64 value)
+int
+session_lookup_add_connection (transport_connection_t * tc, u64 value)
{
- session_lookup_t *sl = &session_lookup;
+ session_table_t *st;
session_kv4_t kv4;
session_kv6_t kv6;
+ st = session_table_get_or_alloc_for_connection (tc);
+ if (!st)
+ return -1;
if (tc->is_ip4)
{
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 */ );
+ return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4,
+ 1 /* is_add */ );
}
else
{
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 */ );
+ return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6,
+ 1 /* is_add */ );
}
}
-void
-stream_session_table_add (session_manager_main_t * smm, stream_session_t * s,
- u64 value)
+int
+session_lookup_add_session_endpoint (u32 table_index,
+ session_endpoint_t * sep, u64 value)
{
- transport_connection_t *tc;
+ session_table_t *st;
+ session_kv4_t kv4;
+ session_kv6_t kv6;
- tc = tp_vfts[s->session_type].get_connection (s->connection_index,
- s->thread_index);
- stream_session_table_add_for_tc (tc, value);
+ st = session_table_get (table_index);
+ if (!st)
+ return -1;
+ if (sep->is_ip4)
+ {
+ make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
+ sep->transport_proto);
+ kv4.value = value;
+ return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4, 1);
+ }
+ else
+ {
+ make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
+ sep->transport_proto);
+ kv6.value = value;
+ return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6, 1);
+ }
}
int
-stream_session_table_del_for_tc (transport_connection_t * tc)
+session_lookup_del_session_endpoint (u32 table_index,
+ session_endpoint_t * sep)
{
- session_lookup_t *sl = &session_lookup;
+ session_table_t *st;
session_kv4_t kv4;
session_kv6_t kv6;
+ st = session_table_get (table_index);
+ if (!st)
+ return -1;
+ if (sep->is_ip4)
+ {
+ make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port,
+ sep->transport_proto);
+ return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4, 0);
+ }
+ else
+ {
+ make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
+ sep->transport_proto);
+ return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6, 0);
+ }
+}
+
+/**
+ * Delete transport connection from session table
+ *
+ * @param table_index session table index
+ * @param tc transport connection to be removed
+ *
+ * @return non-zero if failure
+ */
+int
+session_lookup_del_connection (transport_connection_t * tc)
+{
+ session_table_t *st;
+ session_kv4_t kv4;
+ session_kv6_t kv6;
+
+ st = session_table_get_for_connection (tc);
+ if (!st)
+ return -1;
if (tc->is_ip4)
{
make_v4_ss_kv_from_tc (&kv4, tc);
- return clib_bihash_add_del_16_8 (&sl->v4_session_hash, &kv4,
+ return clib_bihash_add_del_16_8 (&st->v4_session_hash, &kv4,
0 /* is_add */ );
}
else
{
make_v6_ss_kv_from_tc (&kv6, tc);
- return clib_bihash_add_del_48_8 (&sl->v6_session_hash, &kv6,
+ return clib_bihash_add_del_48_8 (&st->v6_session_hash, &kv6,
0 /* is_add */ );
}
-
- return 0;
}
int
-stream_session_table_del (stream_session_t * s)
+session_lookup_del_session (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);
+ return session_lookup_del_connection (ts);
}
-
-void
-stream_session_half_open_table_add (transport_connection_t * tc, u64 value)
+u32
+session_lookup_session_endpoint (u32 table_index, session_endpoint_t * sep)
{
- session_lookup_t *sl = &session_lookup;
+ session_table_t *st;
session_kv4_t kv4;
session_kv6_t kv6;
+ int rv;
- if (tc->is_ip4)
+ st = session_table_get (table_index);
+ if (!st)
+ return SESSION_INVALID_INDEX;
+ if (sep->is_ip4)
{
- make_v4_ss_kv_from_tc (&kv4, tc);
- kv4.value = value;
- (void) clib_bihash_add_del_16_8 (&sl->v4_half_open_hash, &kv4,
- 1 /* is_add */ );
+ 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 (u32) kv4.value;
}
else
{
- make_v6_ss_kv_from_tc (&kv6, tc);
- kv6.value = value;
- (void) clib_bihash_add_del_48_8 (&sl->v6_half_open_hash, &kv6,
- 1 /* is_add */ );
+ 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 (u32) kv6.value;
}
+ return SESSION_INVALID_INDEX;
}
-void
-stream_session_half_open_table_del (transport_connection_t * tc)
+u32
+session_lookup_local_session_endpoint (u32 table_index,
+ session_endpoint_t * sep)
{
- session_lookup_t *sl = &session_lookup;
+ session_table_t *st;
session_kv4_t kv4;
session_kv6_t kv6;
+ int rv;
- if (tc->is_ip4)
+ st = session_table_get (table_index);
+ if (!st)
+ return SESSION_INVALID_INDEX;
+ if (sep->is_ip4)
{
- make_v4_ss_kv_from_tc (&kv4, tc);
- clib_bihash_add_del_16_8 (&sl->v4_half_open_hash, &kv4,
- 0 /* is_add */ );
+ 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 (u32) kv4.value;
+
+ /*
+ * Zero out the ip. Logic is that connect to local ips, say
+ * 127.0.0.1:port, can match 0.0.0.0:port
+ */
+ kv4.key[0] = 0;
+ rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
+ if (rv == 0)
+ return (u32) kv4.value;
}
else
{
- make_v6_ss_kv_from_tc (&kv6, tc);
- clib_bihash_add_del_48_8 (&sl->v6_half_open_hash, &kv6,
- 0 /* is_add */ );
+ 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 (u32) kv6.value;
+
+ /*
+ * Zero out the ip. Same logic as above.
+ */
+ kv6.key[0] = kv6.key[1] = 0;
+ rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
+ if (rv == 0)
+ return (u32) kv6.value;
}
+ return SESSION_INVALID_INDEX;
}
-stream_session_t *
-stream_session_lookup_listener4 (ip4_address_t * lcl, u16 lcl_port, u8 proto)
+static stream_session_t *
+session_lookup_listener4_i (session_table_t * st, 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);
+ rv = clib_bihash_search_inline_16_8 (&st->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);
+ 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 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_listener4 (u32 fib_index, ip4_address_t * lcl, u16 lcl_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;
+ session_table_t *st;
+ st = session_table_get_for_fib_index (FIB_PROTOCOL_IP4, fib_index);
+ if (!st)
+ return 0;
+ return session_lookup_listener4_i (st, lcl, lcl_port, proto);
}
-stream_session_t *
-stream_session_lookup_listener6 (ip6_address_t * lcl, u16 lcl_port, u8 proto)
+static stream_session_t *
+session_lookup_listener6_i (session_table_t * st, 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);
+ rv = clib_bihash_search_inline_48_8 (&st->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);
+ 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 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_listener6 (u32 fib_index, ip6_address_t * lcl, u16 lcl_port,
+ u8 proto)
{
- session_lookup_t *sl = &session_lookup;
- session_kv6_t kv6;
- stream_session_t *s;
- int rv;
+ session_table_t *st;
+ st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index);
+ if (!st)
+ return 0;
+ return session_lookup_listener6_i (st, lcl, lcl_port, proto);
+}
- 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);
+stream_session_t *
+session_lookup_listener (u32 table_index, session_endpoint_t * sep)
+{
+ session_table_t *st;
+ st = session_table_get (table_index);
+ if (!st)
+ return 0;
+ if (sep->is_ip4)
+ return session_lookup_listener4_i (st, &sep->ip.ip4, sep->port,
+ sep->transport_proto);
+ else
+ return session_lookup_listener6_i (st, &sep->ip.ip6, sep->port,
+ sep->transport_proto);
+ return 0;
+}
- /* If nothing is found, check if any listener is available */
- if ((s = stream_session_lookup_listener6 (lcl, lcl_port, proto)))
- return s;
+int
+session_lookup_add_half_open (transport_connection_t * tc, u64 value)
+{
+ session_table_t *st;
+ session_kv4_t kv4;
+ session_kv6_t kv6;
- /* 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;
+ st = session_table_get_or_alloc_for_connection (tc);
+ if (!st)
+ return 0;
+ if (tc->is_ip4)
+ {
+ make_v4_ss_kv_from_tc (&kv4, tc);
+ kv4.value = value;
+ return clib_bihash_add_del_16_8 (&st->v4_half_open_hash, &kv4,
+ 1 /* is_add */ );
+ }
+ else
+ {
+ make_v6_ss_kv_from_tc (&kv6, tc);
+ kv6.value = value;
+ return clib_bihash_add_del_48_8 (&st->v6_half_open_hash, &kv6,
+ 1 /* is_add */ );
+ }
}
-stream_session_t *
-stream_session_lookup_listener (ip46_address_t * lcl, u16 lcl_port, u8 proto)
+int
+session_lookup_del_half_open (transport_connection_t * tc)
{
- switch (proto)
+ session_table_t *st;
+ session_kv4_t kv4;
+ session_kv6_t kv6;
+
+ st = session_table_get_for_connection (tc);
+ if (!st)
+ return -1;
+ if (tc->is_ip4)
{
- 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;
+ make_v4_ss_kv_from_tc (&kv4, tc);
+ return clib_bihash_add_del_16_8 (&st->v4_half_open_hash, &kv4,
+ 0 /* is_add */ );
+ }
+ else
+ {
+ make_v6_ss_kv_from_tc (&kv6, tc);
+ return clib_bihash_add_del_48_8 (&st->v6_half_open_hash, &kv6,
+ 0 /* is_add */ );
}
- 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_half_open_handle (transport_connection_t * tc)
{
- session_lookup_t *sl = &session_lookup;
+ session_table_t *st;
session_kv4_t kv4;
session_kv6_t kv6;
int rv;
- switch (proto)
+ st = session_table_get_for_fib_index (transport_connection_fib_proto (tc),
+ tc->fib_index);
+ if (!st)
+ return HALF_OPEN_LOOKUP_INVALID_VALUE;
+ if (tc->is_ip4)
{
- 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);
-
+ make_v4_ss_kv (&kv4, &tc->lcl_ip.ip4, &tc->rmt_ip.ip4, tc->lcl_port,
+ tc->rmt_port, tc->transport_proto);
+ rv = clib_bihash_search_inline_16_8 (&st->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);
-
+ }
+ else
+ {
+ make_v6_ss_kv (&kv6, &tc->lcl_ip.ip6, &tc->rmt_ip.ip6, tc->lcl_port,
+ tc->rmt_port, tc->transport_proto);
+ rv = clib_bihash_search_inline_48_8 (&st->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)
+session_lookup_half_open_connection (u64 handle, u8 proto, u8 is_ip4)
{
- u64 handle;
- handle =
- stream_session_half_open_lookup_handle (lcl, rmt, lcl_port, rmt_port,
- proto);
+ u32 sst;
+
if (handle != HALF_OPEN_LOOKUP_INVALID_VALUE)
- return tp_vfts[proto].get_half_open (handle & 0xFFFFFFFF);
+ {
+ sst = session_type_from_proto_and_ip (proto, is_ip4);
+ return tp_vfts[sst].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);
-}
-
+/**
+ * Lookup connection with ip4 and transport layer information
+ *
+ * This is used on the fast path so it needs to be fast. Thereby,
+ * duplication of code and 'hacks' allowed.
+ *
+ * The lookup is incremental and returns whenever something is matched. The
+ * steps are:
+ * - Try to find an established session
+ * - Try to find a fully-formed or local source wildcarded (listener bound to
+ * all interfaces) listener session
+ * - Try to find a half-open connection
+ * - return 0
+ *
+ * @param fib_index index of fib wherein the connection was received
+ * @param lcl local ip4 address
+ * @param rmt remote ip4 address
+ * @param lcl_port local port
+ * @param rmt_port remote port
+ * @param proto transport protocol (e.g., tcp, udp)
+ * @param thread_index thread index for request
+ *
+ * @return pointer to transport connection, if one is found, 0 otherwise
+ */
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_connection_wt4 (u32 fib_index, ip4_address_t * lcl,
+ ip4_address_t * rmt, u16 lcl_port,
+ u16 rmt_port, u8 proto, u32 thread_index)
{
- session_lookup_t *sl = &session_lookup;
+ session_table_t *st;
session_kv4_t kv4;
stream_session_t *s;
int rv;
+ st = session_table_get_for_fib_index (FIB_PROTOCOL_IP4, fib_index);
+ if (PREDICT_FALSE (!st))
+ return 0;
+
/* 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);
+ rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
if (rv == 0)
{
- s = stream_session_get_tsi (kv4.value, my_thread_index);
+ 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,
- my_thread_index);
+ thread_index);
}
/* If nothing is found, check if any listener is available */
- s = stream_session_lookup_listener4 (lcl, lcl_port, proto);
+ s = session_lookup_listener4_i (st, 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);
+ rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4);
if (rv == 0)
- return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF);
+ {
+ u32 sst = session_type_from_proto_and_ip (proto, 1);
+ return tp_vfts[sst].get_half_open (kv4.value & 0xFFFFFFFF);
+ }
return 0;
}
+/**
+ * Lookup connection with ip4 and transport layer information
+ *
+ * Not optimized. This is used on the fast path so it needs to be fast.
+ * Thereby, duplication of code and 'hacks' allowed. Lookup logic is identical
+ * to that of @ref session_lookup_connection_wt4
+ *
+ * @param fib_index index of the fib wherein the connection was received
+ * @param lcl local ip4 address
+ * @param rmt remote ip4 address
+ * @param lcl_port local port
+ * @param rmt_port remote port
+ * @param proto transport protocol (e.g., tcp, udp)
+ *
+ * @return pointer to transport connection, if one is found, 0 otherwise
+ */
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_connection4 (u32 fib_index, ip4_address_t * lcl,
+ ip4_address_t * rmt, u16 lcl_port, u16 rmt_port,
+ u8 proto)
{
- session_lookup_t *sl = &session_lookup;
+ session_table_t *st;
session_kv4_t kv4;
stream_session_t *s;
int rv;
+ st = session_table_get_for_fib_index (FIB_PROTOCOL_IP4, fib_index);
+ if (PREDICT_FALSE (!st))
+ return 0;
+
/* 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);
+ rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
if (rv == 0)
{
- s = stream_session_get_from_handle (kv4.value);
+ s = 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);
+ s = session_lookup_listener4_i (st, 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);
+ rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4);
if (rv == 0)
- return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF);
+ {
+ u32 sst = session_type_from_proto_and_ip (proto, 1);
+ return tp_vfts[sst].get_half_open (kv4.value & 0xFFFFFFFF);
+ }
return 0;
}
+/**
+ * Lookup session with ip4 and transport layer information
+ *
+ * Lookup logic is identical to that of @ref session_lookup_connection_wt4 but
+ * this returns a session as opposed to a transport connection;
+ */
+stream_session_t *
+session_lookup4 (u32 fib_index, ip4_address_t * lcl, ip4_address_t * rmt,
+ u16 lcl_port, u16 rmt_port, u8 proto)
+{
+ session_table_t *st;
+ session_kv4_t kv4;
+ stream_session_t *s;
+ int rv;
+
+ st = session_table_get_for_fib_index (FIB_PROTOCOL_IP4, fib_index);
+ if (PREDICT_FALSE (!st))
+ return 0;
+
+ /* Lookup session amongst established ones */
+ make_v4_ss_kv (&kv4, lcl, rmt, lcl_port, rmt_port, proto);
+ rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4);
+ if (rv == 0)
+ return session_get_from_handle (kv4.value);
+
+ /* If nothing is found, check if any listener is available */
+ if ((s = session_lookup_listener4_i (st, lcl, lcl_port, proto)))
+ return s;
+
+ /* Finally, try half-open connections */
+ rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4);
+ if (rv == 0)
+ return session_get_from_handle (kv4.value);
+ return 0;
+}
+
+/**
+ * Lookup connection with ip6 and transport layer information
+ *
+ * This is used on the fast path so it needs to be fast. Thereby,
+ * duplication of code and 'hacks' allowed.
+ *
+ * The lookup is incremental and returns whenever something is matched. The
+ * steps are:
+ * - Try to find an established session
+ * - Try to find a fully-formed or local source wildcarded (listener bound to
+ * all interfaces) listener session
+ * - Try to find a half-open connection
+ * - return 0
+ *
+ * @param fib_index index of the fib wherein the connection was received
+ * @param lcl local ip6 address
+ * @param rmt remote ip6 address
+ * @param lcl_port local port
+ * @param rmt_port remote port
+ * @param proto transport protocol (e.g., tcp, udp)
+ * @param thread_index thread index for request
+ *
+ * @return pointer to transport connection, if one is found, 0 otherwise
+ */
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_connection_wt6 (u32 fib_index, ip6_address_t * lcl,
+ ip6_address_t * rmt, u16 lcl_port,
+ u16 rmt_port, u8 proto, u32 thread_index)
{
- session_lookup_t *sl = &session_lookup;
+ session_table_t *st;
stream_session_t *s;
session_kv6_t kv6;
int rv;
+ st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index);
+ if (PREDICT_FALSE (!st))
+ return 0;
+
make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
- rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
+ rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
if (rv == 0)
{
- s = stream_session_get_tsi (kv6.value, my_thread_index);
+ 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,
- my_thread_index);
+ thread_index);
}
/* If nothing is found, check if any listener is available */
- s = stream_session_lookup_listener6 (lcl, lcl_port, proto);
+ s = session_lookup_listener6_i (st, 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);
+ rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6);
if (rv == 0)
- return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF);
+ {
+ u32 sst = session_type_from_proto_and_ip (proto, 1);
+ return tp_vfts[sst].get_half_open (kv6.value & 0xFFFFFFFF);
+ }
return 0;
}
+/**
+ * Lookup connection with ip6 and transport layer information
+ *
+ * Not optimized. This is used on the fast path so it needs to be fast.
+ * Thereby, duplication of code and 'hacks' allowed. Lookup logic is identical
+ * to that of @ref session_lookup_connection_wt4
+ *
+ * @param fib_index index of the fib wherein the connection was received
+ * @param lcl local ip6 address
+ * @param rmt remote ip6 address
+ * @param lcl_port local port
+ * @param rmt_port remote port
+ * @param proto transport protocol (e.g., tcp, udp)
+ *
+ * @return pointer to transport connection, if one is found, 0 otherwise
+ */
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_connection6 (u32 fib_index, ip6_address_t * lcl,
+ ip6_address_t * rmt, u16 lcl_port, u16 rmt_port,
+ u8 proto)
{
- session_lookup_t *sl = &session_lookup;
+ session_table_t *st;
stream_session_t *s;
session_kv6_t kv6;
int rv;
+ st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index);
+ if (PREDICT_FALSE (!st))
+ return 0;
+
make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
- rv = clib_bihash_search_inline_48_8 (&sl->v6_session_hash, &kv6);
+ rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
if (rv == 0)
{
- s = stream_session_get_from_handle (kv6.value);
+ s = 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);
+ s = session_lookup_listener6 (fib_index, 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);
+ 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 0;
+}
+
+/**
+ * Lookup session with ip6 and transport layer information
+ *
+ * Lookup logic is identical to that of @ref session_lookup_connection_wt6 but
+ * this returns a session as opposed to a transport connection;
+ */
+stream_session_t *
+session_lookup6 (u32 fib_index, ip6_address_t * lcl, ip6_address_t * rmt,
+ u16 lcl_port, u16 rmt_port, u8 proto)
+{
+ session_table_t *st;
+ session_kv6_t kv6;
+ stream_session_t *s;
+ int rv;
+
+ st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index);
+ if (PREDICT_FALSE (!st))
+ return 0;
+
+ make_v6_ss_kv (&kv6, lcl, rmt, lcl_port, rmt_port, proto);
+ rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6);
+ if (rv == 0)
+ return session_get_from_handle (kv6.value);
+
+ /* If nothing is found, check if any listener is available */
+ if ((s = session_lookup_listener6_i (st, lcl, lcl_port, proto)))
+ return s;
+
+ /* Finally, try half-open connections */
+ rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6);
if (rv == 0)
- return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF);
+ return session_get_from_handle (kv6.value);
+ return 0;
+}
+u64
+session_lookup_local_listener_make_handle (session_endpoint_t * sep)
+{
+ return ((u64) SESSION_LOCAL_TABLE_PREFIX << 32
+ | (u32) sep->port << 16 | (u32) sep->transport_proto << 8
+ | (u32) sep->is_ip4);
+}
+
+u8
+session_lookup_local_is_handle (u64 handle)
+{
+ if (handle >> 32 == SESSION_LOCAL_TABLE_PREFIX)
+ return 1;
return 0;
}
-#define foreach_hash_table_parameter \
- _(v4,session,buckets,20000) \
- _(v4,session,memory,(64<<20)) \
- _(v6,session,buckets,20000) \
- _(v6,session,memory,(64<<20)) \
- _(v4,halfopen,buckets,20000) \
- _(v4,halfopen,memory,(64<<20)) \
- _(v6,halfopen,buckets,20000) \
- _(v6,halfopen,memory,(64<<20))
+int
+session_lookup_local_listener_parse_handle (u64 handle,
+ session_endpoint_t * sep)
+{
+ u32 local_table_handle;
+ if (handle >> 32 != SESSION_LOCAL_TABLE_PREFIX)
+ return -1;
+ local_table_handle = handle & 0xFFFFFFFFULL;
+ sep->is_ip4 = local_table_handle & 0xff;
+ local_table_handle >>= 8;
+ sep->transport_proto = local_table_handle & 0xff;
+ sep->port = local_table_handle >> 8;
+ return 0;
+}
+
+u8 *
+format_ip4_session_lookup_kvp (u8 * s, va_list * args)
+{
+ clib_bihash_kv_16_8_t *kvp = va_arg (*args, clib_bihash_kv_16_8_t *);
+ u32 is_local = va_arg (*args, u32);
+ u8 *app_name, *str = 0;
+ 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));
+ 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));
+ s = format (s, "%-30v%-30v", str, app_name);
+ }
+ vec_free (app_name);
+ return s;
+}
+
+typedef struct _ip4_session_table_show_ctx_t
+{
+ vlib_main_t *vm;
+ u8 is_local;
+} ip4_session_table_show_ctx_t;
+
+static int
+ip4_session_table_show (clib_bihash_kv_16_8_t * kvp, void *arg)
+{
+ ip4_session_table_show_ctx_t *ctx = arg;
+ vlib_cli_output (ctx->vm, "%U", format_ip4_session_lookup_kvp, kvp,
+ ctx->is_local);
+ return 1;
+}
+
+void
+session_lookup_show_table_entries (vlib_main_t * vm, session_table_t * table,
+ u8 type, u8 is_local)
+{
+ ip4_session_table_show_ctx_t ctx = {
+ .vm = vm,
+ .is_local = is_local,
+ };
+ if (!is_local)
+ vlib_cli_output (vm, "%-40s%-30s", "Session", "Application");
+ else
+ vlib_cli_output (vm, "%-30s%-30s", "Listener", "Application");
+ switch (type)
+ {
+ /* main table v4 */
+ case 0:
+ ip4_session_table_walk (&table->v4_session_hash, ip4_session_table_show,
+ &ctx);
+ break;
+ default:
+ clib_warning ("not supported");
+ }
+}
void
session_lookup_init (void)
{
- session_lookup_t *sl = &session_lookup;
-
-#define _(af,table,parm,value) \
- u32 configured_##af##_##table##_table_##parm = value;
- foreach_hash_table_parameter;
-#undef _
-
-#define _(af,table,parm,value) \
- if (session_manager_main.configured_##af##_##table##_table_##parm) \
- configured_##af##_##table##_table_##parm = \
- session_manager_main.configured_##af##_##table##_table_##parm;
- foreach_hash_table_parameter;
-#undef _
-
- clib_bihash_init_16_8 (&sl->v4_session_hash, "v4 session table",
- configured_v4_session_table_buckets,
- configured_v4_session_table_memory);
- clib_bihash_init_48_8 (&sl->v6_session_hash, "v6 session table",
- configured_v6_session_table_buckets,
- configured_v6_session_table_memory);
- clib_bihash_init_16_8 (&sl->v4_half_open_hash, "v4 half-open table",
- configured_v4_halfopen_table_buckets,
- configured_v4_halfopen_table_memory);
- clib_bihash_init_48_8 (&sl->v6_half_open_hash, "v6 half-open table",
- configured_v6_halfopen_table_buckets,
- configured_v6_halfopen_table_memory);
+ /*
+ * Allocate default table and map it to fib_index 0
+ */
+ session_table_t *st = session_table_alloc ();
+ vec_validate (fib_index_to_table_index[FIB_PROTOCOL_IP4], 0);
+ fib_index_to_table_index[FIB_PROTOCOL_IP4][0] = session_table_index (st);
+ session_table_init (st);
+ st = session_table_alloc ();
+ vec_validate (fib_index_to_table_index[FIB_PROTOCOL_IP6], 0);
+ fib_index_to_table_index[FIB_PROTOCOL_IP6][0] = session_table_index (st);
+ session_table_init (st);
}
/*