diff options
author | Sachin Saxena <sachin.saxena@freescale.com> | 2018-02-28 20:28:52 +0530 |
---|---|---|
committer | Sachin Saxena <sachin.saxena@nxp.com> | 2018-02-28 20:34:56 +0530 |
commit | 0689fce93ba269c48f83a2f70f971b3976d04c90 (patch) | |
tree | 4cc2908df3598507cc1828ac19d8c43b22450ffa /src/vnet/session/application_interface.c | |
parent | 746b57564deede624261ab8a96c94f562f24d22c (diff) | |
parent | d594711a5d79859a7d0bde83a516f7ab52051d9b (diff) |
Merge branch 'stable/1710' of https://gerrit.fd.io/r/vpp into 17101710
Diffstat (limited to 'src/vnet/session/application_interface.c')
-rw-r--r-- | src/vnet/session/application_interface.c | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/src/vnet/session/application_interface.c b/src/vnet/session/application_interface.c new file mode 100644 index 00000000..7e7449aa --- /dev/null +++ b/src/vnet/session/application_interface.c @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <vnet/session/application_interface.h> + +#include <vnet/session/session.h> +#include <vlibmemory/api.h> +#include <vnet/dpo/load_balance.h> +#include <vnet/fib/ip4_fib.h> + +/** @file + VPP's application/session API bind/unbind/connect/disconnect calls +*/ + +static u8 +ip_is_zero (ip46_address_t * ip46_address, u8 is_ip4) +{ + if (is_ip4) + return (ip46_address->ip4.as_u32 == 0); + else + return (ip46_address->as_u64[0] == 0 && ip46_address->as_u64[1] == 0); +} + +static u8 +ip_is_local (ip46_address_t * ip46_address, u8 is_ip4) +{ + fib_node_index_t fei; + fib_entry_flag_t flags; + fib_prefix_t prefix; + + /* Check if requester is local */ + if (is_ip4) + { + prefix.fp_len = 32; + prefix.fp_proto = FIB_PROTOCOL_IP4; + } + else + { + prefix.fp_len = 128; + prefix.fp_proto = FIB_PROTOCOL_IP6; + } + + clib_memcpy (&prefix.fp_addr, ip46_address, sizeof (ip46_address_t)); + fei = fib_table_lookup (0, &prefix); + flags = fib_entry_get_flags (fei); + + return (flags & FIB_ENTRY_FLAG_LOCAL); +} + +int +api_parse_session_handle (u64 handle, u32 * session_index, u32 * thread_index) +{ + session_manager_main_t *smm = vnet_get_session_manager_main (); + stream_session_t *pool; + + *thread_index = handle & 0xFFFFFFFF; + *session_index = handle >> 32; + + if (*thread_index >= vec_len (smm->sessions)) + return VNET_API_ERROR_INVALID_VALUE; + + pool = smm->sessions[*thread_index]; + + if (pool_is_free_index (pool, *session_index)) + return VNET_API_ERROR_INVALID_VALUE_2; + + return 0; +} + +int +vnet_bind_i (u32 app_index, session_type_t sst, + transport_endpoint_t * tep, u64 * handle) +{ + application_t *app; + stream_session_t *listener; + + app = application_get_if_valid (app_index); + if (!app) + { + clib_warning ("app not attached"); + return VNET_API_ERROR_APPLICATION_NOT_ATTACHED; + } + + listener = stream_session_lookup_listener (&tep->ip, tep->port, sst); + if (listener) + return VNET_API_ERROR_ADDRESS_IN_USE; + + if (!ip_is_zero (&tep->ip, tep->is_ip4) + && !ip_is_local (&tep->ip, tep->is_ip4)) + return VNET_API_ERROR_INVALID_VALUE_2; + + /* Setup listen path down to transport */ + return application_start_listen (app, sst, tep, handle); +} + +int +vnet_unbind_i (u32 app_index, u64 handle) +{ + application_t *app = application_get_if_valid (app_index); + + if (!app) + { + clib_warning ("app (%d) not attached", app_index); + return VNET_API_ERROR_APPLICATION_NOT_ATTACHED; + } + + /* Clear the listener */ + return application_stop_listen (app, handle); +} + +int +vnet_connect_i (u32 app_index, u32 api_context, session_type_t sst, + transport_endpoint_t * tep, void *mp) +{ + stream_session_t *listener; + application_t *server, *app; + + /* + * Figure out if connecting to a local server + */ + listener = stream_session_lookup_listener (&tep->ip, tep->port, sst); + if (listener) + { + server = application_get (listener->app_index); + + /* + * Server is willing to have a direct fifo connection created + * instead of going through the state machine, etc. + */ + if (server->flags & APP_OPTIONS_FLAGS_USE_FIFO) + return server->cb_fns. + redirect_connect_callback (server->api_client_index, mp); + } + + /* + * Not connecting to a local server. Create regular session + */ + app = application_get (app_index); + return application_open_session (app, sst, tep, api_context); +} + +/** + * unformat a vnet URI + * + * fifo://name + * tcp://ip46-addr:port + * udp://ip46-addr:port + * + * u8 ip46_address[16]; + * u16 port_in_host_byte_order; + * stream_session_type_t sst; + * u8 *fifo_name; + * + * if (unformat (input, "%U", unformat_vnet_uri, &ip46_address, + * &sst, &port, &fifo_name)) + * etc... + * + */ +uword +unformat_vnet_uri (unformat_input_t * input, va_list * args) +{ + session_type_t *sst = va_arg (*args, session_type_t *); + transport_endpoint_t *tep = va_arg (*args, transport_endpoint_t *); + + if (unformat (input, "tcp://%U/%d", unformat_ip4_address, &tep->ip.ip4, + &tep->port)) + { + *sst = SESSION_TYPE_IP4_TCP; + tep->port = clib_host_to_net_u16 (tep->port); + tep->is_ip4 = 1; + return 1; + } + if (unformat (input, "udp://%U/%d", unformat_ip4_address, &tep->ip.ip4, + &tep->port)) + { + *sst = SESSION_TYPE_IP4_UDP; + tep->port = clib_host_to_net_u16 (tep->port); + tep->is_ip4 = 1; + return 1; + } + if (unformat (input, "udp://%U/%d", unformat_ip6_address, &tep->ip.ip6, + &tep->port)) + { + *sst = SESSION_TYPE_IP6_UDP; + tep->port = clib_host_to_net_u16 (tep->port); + return 1; + } + if (unformat (input, "tcp://%U/%d", unformat_ip6_address, &tep->ip.ip6, + &tep->port)) + { + *sst = SESSION_TYPE_IP6_TCP; + tep->port = clib_host_to_net_u16 (tep->port); + return 1; + } + + return 0; +} + +static u8 *cache_uri; +static session_type_t cache_sst; +static transport_endpoint_t *cache_tep; + +int +parse_uri (char *uri, session_type_t * sst, transport_endpoint_t * tep) +{ + unformat_input_t _input, *input = &_input; + + if (cache_uri && !strncmp (uri, (char *) cache_uri, vec_len (cache_uri))) + { + *sst = cache_sst; + *tep = *cache_tep; + return 0; + } + + /* Make sure */ + uri = (char *) format (0, "%s%c", uri, 0); + + /* Parse uri */ + unformat_init_string (input, uri, strlen (uri)); + if (!unformat (input, "%U", unformat_vnet_uri, sst, tep)) + { + unformat_free (input); + return VNET_API_ERROR_INVALID_VALUE; + } + unformat_free (input); + + vec_free (cache_uri); + cache_uri = (u8 *) uri; + cache_sst = *sst; + if (cache_tep) + clib_mem_free (cache_tep); + cache_tep = clib_mem_alloc (sizeof (*tep)); + *cache_tep = *tep; + + return 0; +} + +/** + * Attaches application. + * + * Allocates a vpp app, i.e., a structure that keeps back pointers + * to external app and a segment manager for shared memory fifo based + * communication with the external app. + */ +int +vnet_application_attach (vnet_app_attach_args_t * a) +{ + application_t *app = 0; + segment_manager_t *sm; + u8 *seg_name; + int rv; + + app = application_new (); + if ((rv = application_init (app, a->api_client_index, a->options, + a->session_cb_vft))) + return rv; + + a->app_event_queue_address = pointer_to_uword (app->event_queue); + sm = segment_manager_get (app->first_segment_manager); + segment_manager_get_segment_info (sm->segment_indices[0], + &seg_name, &a->segment_size); + + a->segment_name_length = vec_len (seg_name); + a->segment_name = seg_name; + ASSERT (vec_len (a->segment_name) <= 128); + a->app_index = app->index; + return 0; +} + +int +vnet_application_detach (vnet_app_detach_args_t * a) +{ + application_t *app; + app = application_get_if_valid (a->app_index); + + if (!app) + { + clib_warning ("app not attached"); + return VNET_API_ERROR_APPLICATION_NOT_ATTACHED; + } + + application_del (app); + return 0; +} + +int +vnet_bind_uri (vnet_bind_args_t * a) +{ + session_type_t sst = SESSION_N_TYPES; + transport_endpoint_t tep; + int rv; + + memset (&tep, 0, sizeof (tep)); + rv = parse_uri (a->uri, &sst, &tep); + if (rv) + return rv; + + if ((rv = vnet_bind_i (a->app_index, sst, &tep, &a->handle))) + return rv; + + return 0; +} + +int +vnet_unbind_uri (vnet_unbind_args_t * a) +{ + session_type_t sst = SESSION_N_TYPES; + stream_session_t *listener; + transport_endpoint_t tep; + int rv; + + rv = parse_uri (a->uri, &sst, &tep); + if (rv) + return rv; + + listener = stream_session_lookup_listener (&tep.ip, + clib_host_to_net_u16 (tep.port), + sst); + if (!listener) + return VNET_API_ERROR_ADDRESS_NOT_IN_USE; + + return vnet_unbind_i (a->app_index, listen_session_get_handle (listener)); +} + +int +vnet_connect_uri (vnet_connect_args_t * a) +{ + transport_endpoint_t tep; + session_type_t sst; + int rv; + + /* Parse uri */ + memset (&tep, 0, sizeof (tep)); + rv = parse_uri (a->uri, &sst, &tep); + if (rv) + return rv; + + return vnet_connect_i (a->app_index, a->api_context, sst, &tep, a->mp); +} + +int +vnet_disconnect_session (vnet_disconnect_args_t * a) +{ + u32 index, thread_index; + stream_session_t *s; + + stream_session_parse_handle (a->handle, &index, &thread_index); + s = stream_session_get_if_valid (index, thread_index); + + if (!s || s->app_index != a->app_index) + return VNET_API_ERROR_INVALID_VALUE; + + /* We're peeking into another's thread pool. Make sure */ + ASSERT (s->session_index == index); + + session_send_session_evt_to_thread (a->handle, FIFO_EVENT_DISCONNECT, + thread_index); + return 0; +} + +int +vnet_bind (vnet_bind_args_t * a) +{ + session_type_t sst = SESSION_N_TYPES; + int rv; + + sst = session_type_from_proto_and_ip (a->proto, a->tep.is_ip4); + if ((rv = vnet_bind_i (a->app_index, sst, &a->tep, &a->handle))) + return rv; + + return 0; +} + +int +vnet_unbind (vnet_unbind_args_t * a) +{ + return vnet_unbind_i (a->app_index, a->handle); +} + +int +vnet_connect (vnet_connect_args_t * a) +{ + session_type_t sst; + + sst = session_type_from_proto_and_ip (a->proto, a->tep.is_ip4); + return vnet_connect_i (a->app_index, a->api_context, sst, &a->tep, a->mp); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |