X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fsession%2Fsession_lookup.c;h=9ce0b1a22eb97b348cb798e6b958391ffc2317d6;hb=f8f516a8b0ccab2f5d9796f90419bf2661c750af;hp=796d93ec33e4edea14250c1a5914e2cb5364fdbe;hpb=cea194d8f973a2f2b5ef72d212533057174cc70a;p=vpp.git diff --git a/src/vnet/session/session_lookup.c b/src/vnet/session/session_lookup.c index 796d93ec33e..9ce0b1a22eb 100644 --- a/src/vnet/session/session_lookup.c +++ b/src/vnet/session/session_lookup.c @@ -113,10 +113,24 @@ make_v4_listener_kv (session_kv4_t * kv, ip4_address_t * lcl, u16 lcl_port, } always_inline void -make_v4_ss_kv_from_tc (session_kv4_t * kv, transport_connection_t * t) +make_v4_proxy_kv (session_kv4_t * kv, ip4_address_t * lcl, u8 proto) { - make_v4_ss_kv (kv, &t->lcl_ip.ip4, &t->rmt_ip.ip4, t->lcl_port, t->rmt_port, - session_type_from_proto_and_ip (t->transport_proto, 1)); + 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 = 0; + 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 * tc) +{ + make_v4_ss_kv (kv, &tc->lcl_ip.ip4, &tc->rmt_ip.ip4, tc->lcl_port, + tc->rmt_port, tc->proto); } always_inline void @@ -156,33 +170,59 @@ make_v6_listener_kv (session_kv6_t * kv, ip6_address_t * lcl, u16 lcl_port, } always_inline void -make_v6_ss_kv_from_tc (session_kv6_t * kv, transport_connection_t * t) +make_v6_proxy_kv (session_kv6_t * kv, ip6_address_t * lcl, u8 proto) { - make_v6_ss_kv (kv, &t->lcl_ip.ip6, &t->rmt_ip.ip6, t->lcl_port, t->rmt_port, - session_type_from_proto_and_ip (t->transport_proto, 0)); + 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 = 0; + 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 * tc) +{ + make_v6_ss_kv (kv, &tc->lcl_ip.ip6, &tc->rmt_ip.ip6, tc->lcl_port, + tc->rmt_port, tc->proto); +} static session_table_t * -session_table_get_or_alloc_for_connection (transport_connection_t * tc) +session_table_get_or_alloc (u8 fib_proto, u8 fib_index) { 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) + u32 table_index; + if (vec_len (fib_index_to_table_index[fib_proto]) <= 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; + vec_validate (fib_index_to_table_index[fib_proto], fib_index); + fib_index_to_table_index[fib_proto][fib_index] = table_index; + st->active_fib_proto = fib_proto; + session_table_init (st, fib_proto); return st; } else { - table_index = fib_index_to_table_index[fib_proto][tc->fib_index]; + table_index = fib_index_to_table_index[fib_proto][fib_index]; return session_table_get (table_index); } } +static session_table_t * +session_table_get_or_alloc_for_connection (transport_connection_t * tc) +{ + u32 fib_proto; + fib_proto = transport_connection_fib_proto (tc); + return session_table_get_or_alloc (fib_proto, tc->fib_index); +} + static session_table_t * session_table_get_for_connection (transport_connection_t * tc) { @@ -333,61 +373,209 @@ session_lookup_del_connection (transport_connection_t * tc) int session_lookup_del_session (stream_session_t * s) { + transport_proto_t tp = session_get_transport_proto (s); transport_connection_t *ts; - ts = tp_vfts[s->session_type].get_connection (s->connection_index, - s->thread_index); + ts = tp_vfts[tp].get_connection (s->connection_index, s->thread_index); return session_lookup_del_connection (ts); } -u32 -session_lookup_session_endpoint (u32 table_index, session_endpoint_t * sep) +static u8 +session_lookup_action_index_is_valid (u32 action_index) +{ + if (action_index == SESSION_RULES_TABLE_ACTION_ALLOW + || action_index == SESSION_RULES_TABLE_INVALID_INDEX) + return 0; + return 1; +} + +static u64 +session_lookup_action_to_handle (u32 action_index) +{ + switch (action_index) + { + case SESSION_RULES_TABLE_ACTION_DROP: + return SESSION_DROP_HANDLE; + case SESSION_RULES_TABLE_ACTION_ALLOW: + case SESSION_RULES_TABLE_INVALID_INDEX: + return SESSION_INVALID_HANDLE; + default: + /* application index */ + return action_index; + } +} + +static stream_session_t * +session_lookup_app_listen_session (u32 app_index, u8 fib_proto, + u8 transport_proto) { + application_t *app; + app = application_get_if_valid (app_index); + if (!app) + return 0; + + return application_first_listener (app, fib_proto, transport_proto); +} + +static stream_session_t * +session_lookup_action_to_session (u32 action_index, u8 fib_proto, + u8 transport_proto) +{ + u32 app_index; + app_index = session_lookup_action_to_handle (action_index); + /* Nothing sophisticated for now, action index is app index */ + return session_lookup_app_listen_session (app_index, fib_proto, + transport_proto); +} + +/** UNUSED */ +stream_session_t * +session_lookup_rules_table_session4 (session_table_t * st, u8 proto, + ip4_address_t * lcl, u16 lcl_port, + ip4_address_t * rmt, u16 rmt_port) +{ + session_rules_table_t *srt = &st->session_rules[proto]; + u32 action_index, app_index; + action_index = session_rules_table_lookup4 (srt, lcl, rmt, lcl_port, + rmt_port); + app_index = session_lookup_action_to_handle (action_index); + /* Nothing sophisticated for now, action index is app index */ + return session_lookup_app_listen_session (app_index, FIB_PROTOCOL_IP4, + proto); +} + +/** UNUSED */ +stream_session_t * +session_lookup_rules_table_session6 (session_table_t * st, u8 proto, + ip6_address_t * lcl, u16 lcl_port, + ip6_address_t * rmt, u16 rmt_port) +{ + session_rules_table_t *srt = &st->session_rules[proto]; + u32 action_index, app_index; + action_index = session_rules_table_lookup6 (srt, lcl, rmt, lcl_port, + rmt_port); + app_index = session_lookup_action_to_handle (action_index); + return session_lookup_app_listen_session (app_index, FIB_PROTOCOL_IP6, + proto); +} + +/** + * Lookup listener for session endpoint in table + * + * @param table_index table where the endpoint should be looked up + * @param sep session endpoint to be looked up + * @param use_rules flag that indicates if the session rules of the table + * should be used + * @return invalid handle if nothing is found, the handle of a valid listener + * or an action derived handle if a rule is hit + */ +u64 +session_lookup_endpoint_listener (u32 table_index, session_endpoint_t * sep, + u8 use_rules) +{ + session_rules_table_t *srt; session_table_t *st; - session_kv4_t kv4; - session_kv6_t kv6; + u32 ai; int rv; st = session_table_get (table_index); if (!st) - return SESSION_INVALID_INDEX; + return SESSION_INVALID_HANDLE; if (sep->is_ip4) { + session_kv4_t kv4; + ip4_address_t lcl4; + 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; + return kv4.value; + if (use_rules) + { + memset (&lcl4, 0, sizeof (lcl4)); + srt = &st->session_rules[sep->transport_proto]; + ai = session_rules_table_lookup4 (srt, &lcl4, &sep->ip.ip4, 0, + sep->port); + if (session_lookup_action_index_is_valid (ai)) + return session_lookup_action_to_handle (ai); + } } else { + session_kv6_t kv6; + ip6_address_t lcl6; + 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 kv6.value; + + if (use_rules) + { + memset (&lcl6, 0, sizeof (lcl6)); + srt = &st->session_rules[sep->transport_proto]; + ai = session_rules_table_lookup6 (srt, &lcl6, &sep->ip.ip6, 0, + sep->port); + if (session_lookup_action_index_is_valid (ai)) + return session_lookup_action_to_handle (ai); + } } - return SESSION_INVALID_INDEX; + return SESSION_INVALID_HANDLE; } -u32 -session_lookup_local_session_endpoint (u32 table_index, - session_endpoint_t * sep) +/** + * Look up endpoint in local session table + * + * The result, for now, is an application index and it may in the future + * be extended to a more complicated "action object". The only action we + * emulate now is "drop" and for that we return a special app index. + * + * Lookup logic is to check in order: + * - the rules in the table (connect acls) + * - session sub-table for a listener + * - session sub-table for a local listener (zeroed addr) + * + * @param table_index table where the lookup should be done + * @param sep session endpoint to be looked up + * @return session handle that can be interpreted as an adjacency + */ +u64 +session_lookup_local_endpoint (u32 table_index, session_endpoint_t * sep) { + session_rules_table_t *srt; session_table_t *st; - session_kv4_t kv4; - session_kv6_t kv6; + u32 ai; int rv; st = session_table_get (table_index); if (!st) return SESSION_INVALID_INDEX; + ASSERT (st->is_local); + if (sep->is_ip4) { + session_kv4_t kv4; + ip4_address_t lcl4; + + /* + * Check if endpoint has special rules associated + */ + memset (&lcl4, 0, sizeof (lcl4)); + srt = &st->session_rules[sep->transport_proto]; + ai = session_rules_table_lookup4 (srt, &lcl4, &sep->ip.ip4, 0, + sep->port); + if (session_lookup_action_index_is_valid (ai)) + return session_lookup_action_to_handle (ai); + + /* + * Check if session endpoint is a listener + */ 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; + return kv4.value; /* * Zero out the ip. Logic is that connect to local ips, say @@ -396,15 +584,33 @@ session_lookup_local_session_endpoint (u32 table_index, kv4.key[0] = 0; rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4); if (rv == 0) - return (u32) kv4.value; + return kv4.value; + + /* + * Zero out the port and check if we have proxy + */ + kv4.key[1] = 0; + rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4); + if (rv == 0) + return kv4.value; } else { + session_kv6_t kv6; + ip6_address_t lcl6; + + memset (&lcl6, 0, sizeof (lcl6)); + srt = &st->session_rules[sep->transport_proto]; + ai = session_rules_table_lookup6 (srt, &lcl6, &sep->ip.ip6, 0, + sep->port); + if (session_lookup_action_index_is_valid (ai)) + return session_lookup_action_to_handle (ai); + 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 kv6.value; /* * Zero out the ip. Same logic as above. @@ -412,9 +618,17 @@ session_lookup_local_session_endpoint (u32 table_index, 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 kv6.value; + + /* + * Zero out the port. Same logic as above. + */ + kv6.key[4] = kv6.key[5] = 0; + rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6); + if (rv == 0) + return kv6.value; } - return SESSION_INVALID_INDEX; + return SESSION_INVALID_HANDLE; } static stream_session_t * @@ -423,17 +637,32 @@ session_lookup_listener4_i (session_table_t * st, ip4_address_t * lcl, { session_kv4_t kv4; int rv; + session_type_t session_type; + /* + * First, try a fully formed listener + */ + session_type = session_type_from_proto_and_ip (proto, 1); make_v4_listener_kv (&kv4, lcl, lcl_port, proto); rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4); if (rv == 0) - return session_manager_get_listener (proto, (u32) kv4.value); + return session_manager_get_listener (session_type, (u32) kv4.value); - /* Zero out the lcl ip */ + /* + * Zero out the lcl ip and check if any 0/0 port binds have been done + */ kv4.key[0] = 0; rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4); if (rv == 0) - return session_manager_get_listener (proto, (u32) kv4.value); + return session_manager_get_listener (session_type, (u32) kv4.value); + + /* + * Zero out port and check if we have a proxy set up for our ip + */ + make_v4_proxy_kv (&kv4, lcl, proto); + rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4); + if (rv == 0) + return session_manager_get_listener (session_type, (u32) kv4.value); return 0; } @@ -455,18 +684,24 @@ session_lookup_listener6_i (session_table_t * st, ip6_address_t * lcl, { session_kv6_t kv6; int rv; + session_type_t session_type; + session_type = session_type_from_proto_and_ip (proto, 0); make_v6_listener_kv (&kv6, lcl, lcl_port, proto); rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6); if (rv == 0) - return session_manager_get_listener (proto, (u32) kv6.value); + return session_manager_get_listener (session_type, (u32) kv6.value); /* Zero out the lcl ip */ kv6.key[0] = kv6.key[1] = 0; rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6); if (rv == 0) - return session_manager_get_listener (proto, (u32) kv6.value); + return session_manager_get_listener (session_type, (u32) kv6.value); + make_v6_proxy_kv (&kv6, lcl, proto); + rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6); + if (rv == 0) + return session_manager_get_listener (session_type, (u32) kv6.value); return 0; } @@ -562,7 +797,7 @@ session_lookup_half_open_handle (transport_connection_t * tc) if (tc->is_ip4) { make_v4_ss_kv (&kv4, &tc->lcl_ip.ip4, &tc->rmt_ip.ip4, tc->lcl_port, - tc->rmt_port, tc->transport_proto); + tc->rmt_port, tc->proto); rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4); if (rv == 0) return kv4.value; @@ -570,7 +805,7 @@ session_lookup_half_open_handle (transport_connection_t * tc) else { make_v6_ss_kv (&kv6, &tc->lcl_ip.ip6, &tc->rmt_ip.ip6, tc->lcl_port, - tc->rmt_port, tc->transport_proto); + tc->rmt_port, tc->proto); rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6); if (rv == 0) return kv6.value; @@ -600,9 +835,10 @@ session_lookup_half_open_connection (u64 handle, u8 proto, u8 is_ip4) * The lookup is incremental and returns whenever something is matched. The * steps are: * - Try to find an established session + * - Try to find a half-open connection + * - Try session rules table * - 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 @@ -612,46 +848,68 @@ session_lookup_half_open_connection (u64 handle, u8 proto, u8 is_ip4) * @param rmt_port remote port * @param proto transport protocol (e.g., tcp, udp) * @param thread_index thread index for request + * @param is_filtered return flag that indicates if connection was filtered. * * @return pointer to transport connection, if one is found, 0 otherwise */ transport_connection_t * 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) + u16 rmt_port, u8 proto, u32 thread_index, + u8 * is_filtered) { session_table_t *st; session_kv4_t kv4; stream_session_t *s; + u32 action_index; 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 */ + /* + * 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) { ASSERT ((u32) (kv4.value >> 32) == thread_index); s = session_get (kv4.value & 0xFFFFFFFFULL, thread_index); - return tp_vfts[s->session_type].get_connection (s->connection_index, - thread_index); + return tp_vfts[proto].get_connection (s->connection_index, + thread_index); } - /* If nothing is found, check if any listener is available */ - 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 */ + /* + * Try half-open connections + */ 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); + + /* + * Check the session rules table + */ + action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl, + rmt, lcl_port, rmt_port); + if (session_lookup_action_index_is_valid (action_index)) { - u32 sst = session_type_from_proto_and_ip (proto, 1); - return tp_vfts[sst].get_half_open (kv4.value & 0xFFFFFFFF); + if ((*is_filtered = (action_index == SESSION_RULES_TABLE_ACTION_DROP))) + return 0; + if ((s = session_lookup_action_to_session (action_index, + FIB_PROTOCOL_IP4, proto))) + return tp_vfts[proto].get_listener (s->connection_index); + return 0; } + + /* + * If nothing is found, check if any listener is available + */ + s = session_lookup_listener4_i (st, lcl, lcl_port, proto); + if (s) + return tp_vfts[proto].get_listener (s->connection_index); + return 0; } @@ -679,70 +937,111 @@ session_lookup_connection4 (u32 fib_index, ip4_address_t * lcl, session_table_t *st; session_kv4_t kv4; stream_session_t *s; + u32 action_index; 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 */ + /* + * 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) { s = session_get_from_handle (kv4.value); - return tp_vfts[s->session_type].get_connection (s->connection_index, - s->thread_index); + return tp_vfts[proto].get_connection (s->connection_index, + s->thread_index); } - /* If nothing is found, check if any listener is available */ - 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 */ + /* + * Try half-open connections + */ 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); + + /* + * Check the session rules table + */ + action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl, + rmt, lcl_port, rmt_port); + if (session_lookup_action_index_is_valid (action_index)) { - u32 sst = session_type_from_proto_and_ip (proto, 1); - return tp_vfts[sst].get_half_open (kv4.value & 0xFFFFFFFF); + if (action_index == SESSION_RULES_TABLE_ACTION_DROP) + return 0; + if ((s = session_lookup_action_to_session (action_index, + FIB_PROTOCOL_IP4, proto))) + return tp_vfts[proto].get_listener (s->connection_index); + return 0; } + + /* + * If nothing is found, check if any listener is available + */ + s = session_lookup_listener4_i (st, lcl, lcl_port, proto); + if (s) + return tp_vfts[proto].get_listener (s->connection_index); + 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; + * Important note: this may look into another thread's pool table and + * register as 'peeker'. Caller should call @ref session_pool_remove_peeker as + * if needed as soon as possible. + * + * Lookup logic is similar to that of @ref session_lookup_connection_wt4 but + * this returns a session as opposed to a transport connection and it does not + * try to lookup half-open sessions. + * + * Typically used by dgram connections */ 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_lookup_safe4 (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; + u32 action_index; 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 */ + /* + * 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); + return session_get_from_handle_safe (kv4.value); - /* If nothing is found, check if any listener is available */ + /* + * Check the session rules table + */ + action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl, + rmt, lcl_port, rmt_port); + if (session_lookup_action_index_is_valid (action_index)) + { + if (action_index == SESSION_RULES_TABLE_ACTION_DROP) + return 0; + return session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP4, + proto); + } + + /* + * 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; } @@ -755,9 +1054,10 @@ session_lookup4 (u32 fib_index, ip4_address_t * lcl, ip4_address_t * rmt, * The lookup is incremental and returns whenever something is matched. The * steps are: * - Try to find an established session + * - Try to find a half-open connection + * - Try session rules table * - 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 @@ -773,11 +1073,13 @@ session_lookup4 (u32 fib_index, ip4_address_t * lcl, ip4_address_t * rmt, transport_connection_t * 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) + u16 rmt_port, u8 proto, u32 thread_index, + u8 * is_filtered) { session_table_t *st; stream_session_t *s; session_kv6_t kv6; + u32 action_index; int rv; st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index); @@ -790,23 +1092,33 @@ session_lookup_connection_wt6 (u32 fib_index, ip6_address_t * lcl, { ASSERT ((u32) (kv6.value >> 32) == thread_index); s = session_get (kv6.value & 0xFFFFFFFFULL, thread_index); - return tp_vfts[s->session_type].get_connection (s->connection_index, - thread_index); + return tp_vfts[proto].get_connection (s->connection_index, + thread_index); } - /* If nothing is found, check if any listener is available */ - s = session_lookup_listener6_i (st, lcl, lcl_port, proto); - if (s) - return tp_vfts[s->session_type].get_listener (s->connection_index); - - /* Finally, try half-open connections */ + /* 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); + + /* Check the session rules table */ + action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl, + rmt, lcl_port, rmt_port); + if (session_lookup_action_index_is_valid (action_index)) { - u32 sst = session_type_from_proto_and_ip (proto, 1); - return tp_vfts[sst].get_half_open (kv6.value & 0xFFFFFFFF); + if ((*is_filtered = (action_index == SESSION_RULES_TABLE_ACTION_DROP))) + return 0; + if ((s = session_lookup_action_to_session (action_index, + FIB_PROTOCOL_IP6, proto))) + return tp_vfts[proto].get_listener (s->connection_index); + return 0; } + /* If nothing is found, check if any listener is available */ + s = session_lookup_listener6_i (st, lcl, lcl_port, proto); + if (s) + return tp_vfts[proto].get_listener (s->connection_index); + return 0; } @@ -834,6 +1146,7 @@ session_lookup_connection6 (u32 fib_index, ip6_address_t * lcl, session_table_t *st; stream_session_t *s; session_kv6_t kv6; + u32 action_index; int rv; st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index); @@ -845,39 +1158,57 @@ session_lookup_connection6 (u32 fib_index, ip6_address_t * lcl, if (rv == 0) { s = session_get_from_handle (kv6.value); - return tp_vfts[s->session_type].get_connection (s->connection_index, - s->thread_index); + return tp_vfts[proto].get_connection (s->connection_index, + s->thread_index); } - /* If nothing is found, check if any listener is available */ - s = session_lookup_listener6 (fib_index, lcl, lcl_port, proto); - if (s) - return tp_vfts[s->session_type].get_listener (s->connection_index); - - /* Finally, try half-open connections */ + /* 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); + + /* Check the session rules table */ + action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl, + rmt, lcl_port, rmt_port); + if (session_lookup_action_index_is_valid (action_index)) { - u32 sst = session_type_from_proto_and_ip (proto, 1); - return tp_vfts[sst].get_half_open (kv6.value & 0xFFFFFFFF); + if (action_index == SESSION_RULES_TABLE_ACTION_DROP) + return 0; + if ((s = session_lookup_action_to_session (action_index, + FIB_PROTOCOL_IP6, proto))) + return tp_vfts[proto].get_listener (s->connection_index); + return 0; } + /* If nothing is found, check if any listener is available */ + s = session_lookup_listener6 (fib_index, lcl, lcl_port, proto); + if (s) + return tp_vfts[proto].get_listener (s->connection_index); + 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; + * Important note: this may look into another thread's pool table and + * register as 'peeker'. Caller should call @ref session_pool_remove_peeker as + * if needed as soon as possible. + * + * Lookup logic is similar to that of @ref session_lookup_connection_wt6 but + * this returns a session as opposed to a transport connection and it does not + * try to lookup half-open sessions. + * + * Typically used by dgram connections */ 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_lookup_safe6 (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; + u32 action_index; int rv; st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index); @@ -887,48 +1218,86 @@ session_lookup6 (u32 fib_index, ip6_address_t * lcl, ip6_address_t * rmt, 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); + return session_get_from_handle_safe (kv6.value); + + /* Check the session rules table */ + action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl, + rmt, lcl_port, rmt_port); + if (session_lookup_action_index_is_valid (action_index)) + { + if (action_index == SESSION_RULES_TABLE_ACTION_DROP) + return 0; + return session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP6, + proto); + } /* 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 session_get_from_handle (kv6.value); return 0; } -u64 -session_lookup_local_listener_make_handle (session_endpoint_t * sep) +clib_error_t * +vnet_session_rule_add_del (session_rule_add_del_args_t * args) { - return ((u64) SESSION_LOCAL_TABLE_PREFIX << 32 - | (u32) sep->port << 16 | (u32) sep->transport_proto << 8 - | (u32) sep->is_ip4); + app_namespace_t *app_ns = app_namespace_get (args->appns_index); + session_rules_table_t *srt; + session_table_t *st; + u32 fib_index; + u8 fib_proto; + clib_error_t *error; + + if (!app_ns) + return clib_error_return_code (0, VNET_API_ERROR_APP_INVALID_NS, 0, + "invalid app ns"); + if (args->scope > 3) + return clib_error_return_code (0, VNET_API_ERROR_INVALID_VALUE, 0, + "invalid scope"); + if (args->transport_proto != TRANSPORT_PROTO_TCP + && args->transport_proto != TRANSPORT_PROTO_UDP) + return clib_error_return_code (0, VNET_API_ERROR_INVALID_VALUE, 0, + "invalid transport proto"); + if ((args->scope & SESSION_RULE_SCOPE_GLOBAL) || args->scope == 0) + { + fib_proto = args->table_args.rmt.fp_proto; + fib_index = app_namespace_get_fib_index (app_ns, fib_proto); + st = session_table_get_for_fib_index (fib_proto, fib_index); + srt = &st->session_rules[args->transport_proto]; + if ((error = session_rules_table_add_del (srt, &args->table_args))) + { + clib_error_report (error); + return error; + } + } + if (args->scope & SESSION_RULE_SCOPE_LOCAL) + { + memset (&args->table_args.lcl, 0, sizeof (args->table_args.lcl)); + args->table_args.lcl.fp_proto = args->table_args.rmt.fp_proto; + args->table_args.lcl_port = 0; + st = app_namespace_get_local_table (app_ns); + srt = &st->session_rules[args->transport_proto]; + error = session_rules_table_add_del (srt, &args->table_args); + } + return error; } -u8 -session_lookup_local_is_handle (u64 handle) +/** + * Mark (global) tables as pertaining to app ns + */ +void +session_lookup_set_tables_appns (app_namespace_t * app_ns) { - if (handle >> 32 == SESSION_LOCAL_TABLE_PREFIX) - return 1; - return 0; -} + session_table_t *st; + u32 fib_index; + u8 fp; -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; + for (fp = 0; fp < ARRAY_LEN (fib_index_to_table_index); fp++) + { + fib_index = app_namespace_get_fib_index (app_ns, fp); + st = session_table_get_for_fib_index (fp, fib_index); + if (st) + st->appns_index = app_namespace_index (app_ns); + } } u8 * @@ -940,22 +1309,22 @@ format_ip4_session_lookup_kvp (u8 * s, va_list * args) stream_session_t *session; v4_connection_key_t *key = (v4_connection_key_t *) kvp->key; - char *proto = key->proto == TRANSPORT_PROTO_TCP ? "T" : "U"; if (!is_local) { session = session_get_from_handle (kvp->value); app_name = application_name_from_index (session->app_index); - str = format (0, "[%s] %U:%d->%U:%d", proto, format_ip4_address, - &key->src, clib_net_to_host_u16 (key->src_port), - format_ip4_address, &key->dst, - clib_net_to_host_u16 (key->dst_port)); + str = format (0, "[%U] %U:%d->%U:%d", format_transport_proto_short, + key->proto, format_ip4_address, &key->src, + clib_net_to_host_u16 (key->src_port), format_ip4_address, + &key->dst, clib_net_to_host_u16 (key->dst_port)); s = format (s, "%-40v%-30v", str, app_name); } else { app_name = application_name_from_index (kvp->value); - str = format (0, "[%s] %U:%d", proto, format_ip4_address, - &key->src, clib_net_to_host_u16 (key->src_port)); + str = format (0, "[%U] %U:%d", format_transport_proto_short, key->proto, + format_ip4_address, &key->src, + clib_net_to_host_u16 (key->src_port)); s = format (s, "%-30v%-30v", str, app_name); } vec_free (app_name); @@ -1001,6 +1370,258 @@ session_lookup_show_table_entries (vlib_main_t * vm, session_table_t * table, } } +static clib_error_t * +session_rule_command_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + u32 proto = ~0, lcl_port, rmt_port, action = 0, lcl_plen = 0, rmt_plen = 0; + u32 appns_index, scope = 0; + ip46_address_t lcl_ip, rmt_ip; + u8 is_ip4 = 1, conn_set = 0; + u8 fib_proto, is_add = 1, *ns_id = 0; + u8 *tag = 0; + app_namespace_t *app_ns; + clib_error_t *error; + + memset (&lcl_ip, 0, sizeof (lcl_ip)); + memset (&rmt_ip, 0, sizeof (rmt_ip)); + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + is_add = 0; + else if (unformat (input, "add")) + ; + else if (unformat (input, "appns %_%v%_", &ns_id)) + ; + else if (unformat (input, "scope global")) + scope = SESSION_RULE_SCOPE_GLOBAL; + else if (unformat (input, "scope local")) + scope = SESSION_RULE_SCOPE_LOCAL; + else if (unformat (input, "scope all")) + scope = SESSION_RULE_SCOPE_LOCAL | SESSION_RULE_SCOPE_GLOBAL; + else if (unformat (input, "proto %U", unformat_transport_proto, &proto)) + ; + else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip4_address, + &lcl_ip.ip4, &lcl_plen, &lcl_port, + unformat_ip4_address, &rmt_ip.ip4, &rmt_plen, + &rmt_port)) + { + is_ip4 = 1; + conn_set = 1; + } + else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip6_address, + &lcl_ip.ip6, &lcl_plen, &lcl_port, + unformat_ip6_address, &rmt_ip.ip6, &rmt_plen, + &rmt_port)) + { + is_ip4 = 0; + conn_set = 1; + } + else if (unformat (input, "action %d", &action)) + ; + else if (unformat (input, "tag %_%v%_", &tag)) + ; + else + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + } + + if (proto == ~0) + { + vlib_cli_output (vm, "proto must be set"); + return 0; + } + if (is_add && !conn_set && action == ~0) + { + vlib_cli_output (vm, "connection and action must be set for add"); + return 0; + } + if (!is_add && !tag && !conn_set) + { + vlib_cli_output (vm, "connection or tag must be set for delete"); + return 0; + } + if (vec_len (tag) > SESSION_RULE_TAG_MAX_LEN) + { + vlib_cli_output (vm, "tag too long (max u64)"); + return 0; + } + + if (ns_id) + { + app_ns = app_namespace_get_from_id (ns_id); + if (!app_ns) + { + vlib_cli_output (vm, "namespace %v does not exist", ns_id); + return 0; + } + } + else + { + app_ns = app_namespace_get_default (); + } + appns_index = app_namespace_index (app_ns); + + fib_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6; + session_rule_add_del_args_t args = { + .table_args.lcl.fp_addr = lcl_ip, + .table_args.lcl.fp_len = lcl_plen, + .table_args.lcl.fp_proto = fib_proto, + .table_args.rmt.fp_addr = rmt_ip, + .table_args.rmt.fp_len = rmt_plen, + .table_args.rmt.fp_proto = fib_proto, + .table_args.lcl_port = lcl_port, + .table_args.rmt_port = rmt_port, + .table_args.action_index = action, + .table_args.is_add = is_add, + .table_args.tag = tag, + .appns_index = appns_index, + .scope = scope, + }; + error = vnet_session_rule_add_del (&args); + vec_free (tag); + return error; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (session_rule_command, static) = +{ + .path = "session rule", + .short_help = "session rule [add|del] appns proto " + " action ", + .function = session_rule_command_fn, +}; +/* *INDENT-ON* */ + +void +session_lookup_dump_rules_table (u32 fib_index, u8 fib_proto, + u8 transport_proto) +{ + vlib_main_t *vm = vlib_get_main (); + session_rules_table_t *srt; + session_table_t *st; + st = session_table_get_for_fib_index (fib_index, fib_proto); + srt = &st->session_rules[transport_proto]; + session_rules_table_cli_dump (vm, srt, fib_proto); +} + +void +session_lookup_dump_local_rules_table (u32 table_index, u8 fib_proto, + u8 transport_proto) +{ + vlib_main_t *vm = vlib_get_main (); + session_rules_table_t *srt; + session_table_t *st; + st = session_table_get (table_index); + srt = &st->session_rules[transport_proto]; + session_rules_table_cli_dump (vm, srt, fib_proto); +} + +static clib_error_t * +show_session_rules_command_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + u32 transport_proto = ~0, lcl_port, rmt_port, lcl_plen, rmt_plen; + u32 fib_index, scope = 0; + ip46_address_t lcl_ip, rmt_ip; + u8 is_ip4 = 1, show_one = 0; + app_namespace_t *app_ns; + session_rules_table_t *srt; + session_table_t *st; + u8 *ns_id = 0, fib_proto; + + memset (&lcl_ip, 0, sizeof (lcl_ip)); + memset (&rmt_ip, 0, sizeof (rmt_ip)); + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "%U", unformat_transport_proto, &transport_proto)) + ; + else if (unformat (input, "appns %_%v%_", &ns_id)) + ; + else if (unformat (input, "scope global")) + scope = 1; + else if (unformat (input, "scope local")) + scope = 2; + else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip4_address, + &lcl_ip.ip4, &lcl_plen, &lcl_port, + unformat_ip4_address, &rmt_ip.ip4, &rmt_plen, + &rmt_port)) + { + is_ip4 = 1; + show_one = 1; + } + else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip6_address, + &lcl_ip.ip6, &lcl_plen, &lcl_port, + unformat_ip6_address, &rmt_ip.ip6, &rmt_plen, + &rmt_port)) + { + is_ip4 = 0; + show_one = 1; + } + else + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + } + + if (transport_proto == ~0) + { + vlib_cli_output (vm, "transport proto must be set"); + return 0; + } + + if (ns_id) + { + app_ns = app_namespace_get_from_id (ns_id); + if (!app_ns) + { + vlib_cli_output (vm, "appns %v doesn't exist", ns_id); + return 0; + } + } + else + { + app_ns = app_namespace_get_default (); + } + + if (scope == 1 || scope == 0) + { + fib_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6; + fib_index = is_ip4 ? app_ns->ip4_fib_index : app_ns->ip6_fib_index; + st = session_table_get_for_fib_index (fib_proto, fib_index); + } + else + { + st = app_namespace_get_local_table (app_ns); + } + + if (show_one) + { + srt = &st->session_rules[transport_proto]; + session_rules_table_show_rule (vm, srt, &lcl_ip, lcl_port, &rmt_ip, + rmt_port, is_ip4); + return 0; + } + + vlib_cli_output (vm, "%U rules table", format_transport_proto, + transport_proto); + srt = &st->session_rules[transport_proto]; + session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP4); + session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP6); + + vec_free (ns_id); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_session_rules_command, static) = +{ + .path = "show session rules", + .short_help = "show session rules [ appns " + " scope ]", + .function = show_session_rules_command_fn, +}; +/* *INDENT-ON* */ + void session_lookup_init (void) { @@ -1010,11 +1631,13 @@ session_lookup_init (void) 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->active_fib_proto = FIB_PROTOCOL_IP4; + session_table_init (st, FIB_PROTOCOL_IP4); 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); + st->active_fib_proto = FIB_PROTOCOL_IP6; + session_table_init (st, FIB_PROTOCOL_IP6); } /*