X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fsession%2Fsession_lookup.c;h=2168c61257c6da0ffcf6d50dd1a030a46cee0989;hb=1c7104514cd40d2377caca36cf40c13b791bc5aa;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..2168c61257c 100644 --- a/src/vnet/session/session_lookup.c +++ b/src/vnet/session/session_lookup.c @@ -116,7 +116,7 @@ always_inline void make_v4_ss_kv_from_tc (session_kv4_t * kv, transport_connection_t * t) { 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)); + session_type_from_proto_and_ip (t->proto, 1)); } always_inline void @@ -159,7 +159,7 @@ 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, - session_type_from_proto_and_ip (t->transport_proto, 0)); + session_type_from_proto_and_ip (t->proto, 0)); } @@ -339,24 +339,75 @@ session_lookup_del_session (stream_session_t * s) return session_lookup_del_connection (ts); } -u32 +static stream_session_t * +session_lookup_app_listen_session (u32 app_index) +{ + application_t *app; + app = application_get (app_index); + if (!app) + return 0; + + if (application_n_listeners (app) != 1) + { + clib_warning ("there should be one and only one listener %d", + hash_elts (app->listeners_table)); + return 0; + } + + return application_first_listener (app); +} + +stream_session_t * +session_lookup_rules_table4 (session_rules_table_t * srt, u8 proto, + ip4_address_t * lcl, u16 lcl_port, + ip4_address_t * rmt, u16 rmt_port) +{ + u32 action_index; + action_index = session_rules_table_lookup4 (srt, proto, lcl, rmt, lcl_port, + rmt_port); + /* Nothing sophisticated for now, action index is app index */ + return session_lookup_app_listen_session (action_index); +} + +stream_session_t * +session_lookup_rules_table6 (session_rules_table_t * srt, u8 proto, + ip6_address_t * lcl, u16 lcl_port, + ip6_address_t * rmt, u16 rmt_port) +{ + u32 action_index; + action_index = session_rules_table_lookup6 (srt, proto, lcl, rmt, lcl_port, + rmt_port); + return session_lookup_app_listen_session (action_index); +} + +u64 session_lookup_session_endpoint (u32 table_index, session_endpoint_t * sep) { session_table_t *st; session_kv4_t kv4; session_kv6_t kv6; + ip4_address_t lcl4; + ip6_address_t lcl6; + u32 si; int rv; st = session_table_get (table_index); if (!st) - return SESSION_INVALID_INDEX; + return SESSION_INVALID_HANDLE; if (sep->is_ip4) { 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; + + memset (&lcl4, 0, sizeof (lcl4)); + si = + session_rules_table_lookup4 (&st->session_rules, sep->transport_proto, + &lcl4, &sep->ip.ip4, 0, sep->port); + if (si != SESSION_RULES_TABLE_INVALID_INDEX) + return si; } else { @@ -364,9 +415,59 @@ session_lookup_session_endpoint (u32 table_index, session_endpoint_t * sep) 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; + + memset (&lcl6, 0, sizeof (lcl6)); + si = + session_rules_table_lookup6 (&st->session_rules, sep->transport_proto, + &lcl6, &sep->ip.ip6, 0, sep->port); + if (si != SESSION_RULES_TABLE_INVALID_INDEX) + return si; + } + return SESSION_INVALID_HANDLE; +} + +stream_session_t * +session_lookup_global_session_endpoint (session_endpoint_t * sep) +{ + session_table_t *st; + session_kv4_t kv4; + session_kv6_t kv6; + ip4_address_t lcl4; + ip6_address_t lcl6; + u8 fib_proto; + u32 table_index; + int rv; + + fib_proto = session_endpoint_fib_proto (sep); + table_index = session_lookup_get_index_for_fib (fib_proto, sep->fib_index); + st = session_table_get (table_index); + if (!st) + return 0; + if (sep->is_ip4) + { + 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 session_get_from_handle (kv4.value); + memset (&lcl4, 0, sizeof (lcl4)); + return session_lookup_rules_table4 (&st->session_rules, + sep->transport_proto, &lcl4, 0, + &sep->ip.ip4, sep->port); + } + else + { + 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 session_get_from_handle (kv6.value); + memset (&lcl6, 0, sizeof (lcl6)); + return session_lookup_rules_table6 (&st->session_rules, + sep->transport_proto, &lcl6, 0, + &sep->ip.ip6, sep->port); } - return SESSION_INVALID_INDEX; } u32 @@ -376,6 +477,9 @@ session_lookup_local_session_endpoint (u32 table_index, session_table_t *st; session_kv4_t kv4; session_kv6_t kv6; + ip4_address_t lcl4; + ip6_address_t lcl6; + u32 si; int rv; st = session_table_get (table_index); @@ -397,6 +501,13 @@ session_lookup_local_session_endpoint (u32 table_index, rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4); if (rv == 0) return (u32) kv4.value; + + memset (&lcl4, 0, sizeof (lcl4)); + si = + session_rules_table_lookup4 (&st->session_rules, sep->transport_proto, + &lcl4, &sep->ip.ip4, 0, sep->port); + if (si != SESSION_RULES_TABLE_INVALID_INDEX) + return si; } else { @@ -413,6 +524,13 @@ session_lookup_local_session_endpoint (u32 table_index, rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6); if (rv == 0) return (u32) kv6.value; + + memset (&lcl6, 0, sizeof (lcl6)); + si = + session_rules_table_lookup6 (&st->session_rules, sep->transport_proto, + &lcl6, &sep->ip.ip6, 0, sep->port); + if (si != SESSION_RULES_TABLE_INVALID_INDEX) + return si; } return SESSION_INVALID_INDEX; } @@ -562,7 +680,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 +688,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; @@ -591,6 +709,30 @@ session_lookup_half_open_connection (u64 handle, u8 proto, u8 is_ip4) return 0; } +transport_connection_t * +session_lookup_rules_table_connection4 (session_rules_table_t * srt, u8 proto, + ip4_address_t * lcl, u16 lcl_port, + ip4_address_t * rmt, u16 rmt_port) +{ + stream_session_t *s; + s = session_lookup_rules_table4 (srt, proto, lcl, lcl_port, rmt, rmt_port); + if (s) + return tp_vfts[s->session_type].get_listener (s->connection_index); + return 0; +} + +transport_connection_t * +session_lookup_rules_table_connection6 (session_rules_table_t * srt, u8 proto, + ip6_address_t * lcl, u16 lcl_port, + ip6_address_t * rmt, u16 rmt_port) +{ + stream_session_t *s; + s = session_lookup_rules_table6 (srt, proto, lcl, lcl_port, rmt, rmt_port); + if (s) + return tp_vfts[s->session_type].get_listener (s->connection_index); + return 0; +} + /** * Lookup connection with ip4 and transport layer information * @@ -603,6 +745,7 @@ session_lookup_half_open_connection (u64 handle, u8 proto, u8 is_ip4) * - Try to find a fully-formed or local source wildcarded (listener bound to * all interfaces) listener session * - Try to find a half-open connection + * - Try session rules table * - return 0 * * @param fib_index index of fib wherein the connection was received @@ -645,14 +788,18 @@ session_lookup_connection_wt4 (u32 fib_index, ip4_address_t * lcl, 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) { u32 sst = session_type_from_proto_and_ip (proto, 1); return tp_vfts[sst].get_half_open (kv4.value & 0xFFFFFFFF); } - return 0; + + /* Check the session rules table */ + return session_lookup_rules_table_connection4 (&st->session_rules, proto, + lcl, lcl_port, rmt, + rmt_port); } /** @@ -707,18 +854,28 @@ session_lookup_connection4 (u32 fib_index, ip4_address_t * lcl, u32 sst = session_type_from_proto_and_ip (proto, 1); return tp_vfts[sst].get_half_open (kv4.value & 0xFFFFFFFF); } - return 0; + /* Check the session rules table */ + return session_lookup_rules_table_connection4 (&st->session_rules, proto, + lcl, lcl_port, rmt, + rmt_port); } /** * 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; @@ -733,17 +890,13 @@ session_lookup4 (u32 fib_index, ip4_address_t * lcl, ip4_address_t * rmt, 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 */ 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; + return session_lookup_rules_table4 (&st->session_rules, proto, lcl, + lcl_port, rmt, rmt_port); } /** @@ -758,6 +911,7 @@ session_lookup4 (u32 fib_index, ip4_address_t * lcl, ip4_address_t * rmt, * - Try to find a fully-formed or local source wildcarded (listener bound to * all interfaces) listener session * - Try to find a half-open connection + * - Try session rules table * - return 0 * * @param fib_index index of the fib wherein the connection was received @@ -807,7 +961,9 @@ session_lookup_connection_wt6 (u32 fib_index, ip6_address_t * lcl, return tp_vfts[sst].get_half_open (kv6.value & 0xFFFFFFFF); } - return 0; + return session_lookup_rules_table_connection6 (&st->session_rules, proto, + lcl, lcl_port, rmt, + rmt_port); } /** @@ -862,18 +1018,27 @@ session_lookup_connection6 (u32 fib_index, ip6_address_t * lcl, return tp_vfts[sst].get_half_open (kv6.value & 0xFFFFFFFF); } - return 0; + return session_lookup_rules_table_connection6 (&st->session_rules, proto, + lcl, lcl_port, rmt, + rmt_port); } /** * 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; @@ -887,17 +1052,13 @@ 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); /* 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; + return session_lookup_rules_table6 (&st->session_rules, proto, lcl, + lcl_port, rmt, rmt_port); } u64 @@ -931,6 +1092,39 @@ session_lookup_local_listener_parse_handle (u64 handle, return 0; } +clib_error_t * +vnet_session_rule_add_del (session_rule_add_del_args_t * args) +{ + app_namespace_t *app_ns = app_namespace_get (args->appns_index); + 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->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); + if ((error = session_rules_table_add_del (&st->session_rules, + &args->table_args))) + return error; + } + if (args->scope & SESSION_RULE_SCOPE_LOCAL) + { + st = app_namespace_get_local_table (app_ns); + error = + session_rules_table_add_del (&st->session_rules, &args->table_args); + } + return error; +} + u8 * format_ip4_session_lookup_kvp (u8 * s, va_list * args) { @@ -1001,6 +1195,204 @@ 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, rmt_plen; + 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; + app_namespace_t *app_ns; + + 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 + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + } + + if (proto == ~0 || !conn_set || action == ~0) + return clib_error_return (0, "proto, connection and action must be set"); + + if (ns_id) + { + app_ns = app_namespace_get_from_id (ns_id); + if (!app_ns) + return clib_error_return (0, "namespace %v does not exist", ns_id); + } + 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, + .appns_index = appns_index, + .scope = scope, + }; + return vnet_session_rule_add_del (&args); +} + +/* *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* */ + +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_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) + { + session_rules_table_show_rule (vm, &st->session_rules, transport_proto, + &lcl_ip, lcl_port, &rmt_ip, rmt_port, + is_ip4); + return 0; + } + + session_rules_table_cli_dump (vm, &st->session_rules, FIB_PROTOCOL_IP4, + transport_proto); + session_rules_table_cli_dump (vm, &st->session_rules, FIB_PROTOCOL_IP6, + transport_proto); + + 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 proto " + " ]", + .function = show_session_rules_command_fn, +}; +/* *INDENT-ON* */ + void session_lookup_init (void) {