/* * Copyright (c) 2017 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include /* * Pool from which we allocate all applications */ static application_t *app_pool; /* * Hash table of apps by api client index */ static uword *app_by_api_client_index; int application_api_queue_is_full (application_t * app) { unix_shared_memory_queue_t *q; /* builtin servers are always OK */ if (app->api_client_index == ~0) return 0; q = vl_api_client_index_to_input_queue (app->api_client_index); if (!q) return 1; if (q->cursize == q->maxsize) return 1; return 0; } static void application_table_add (application_t * app) { hash_set (app_by_api_client_index, app->api_client_index, app->index); } static void application_table_del (application_t * app) { hash_unset (app_by_api_client_index, app->api_client_index); } application_t * application_lookup (u32 api_client_index) { uword *p; p = hash_get (app_by_api_client_index, api_client_index); if (p) return application_get (p[0]); return 0; } void application_del (application_t * app) { session_manager_main_t *smm = vnet_get_session_manager_main (); api_main_t *am = &api_main; void *oldheap; session_manager_t *sm; if (app->mode == APP_SERVER) { sm = session_manager_get (app->session_manager_index); session_manager_del (smm, sm); } /* Free the event fifo in the /vpe-api shared-memory segment */ oldheap = svm_push_data_heap (am->vlib_rp); if (app->event_queue) unix_shared_memory_queue_free (app->event_queue); svm_pop_heap (oldheap); application_table_del (app); pool_put (app_pool, app); } application_t * application_new (application_type_t type, session_type_t sst, u32 api_client_index, u32 flags, session_cb_vft_t * cb_fns) { session_manager_main_t *smm = vnet_get_session_manager_main (); api_main_t *am = &api_main; application_t *app; void *oldheap; session_manager_t *sm; pool_get (app_pool, app); memset (app, 0, sizeof (*app)); /* Allocate event fifo in the /vpe-api shared-memory segment */ oldheap = svm_push_data_heap (am->vlib_rp); /* Allocate server event queue */ app->event_queue = unix_shared_memory_queue_init (128 /* nels $$$$ config */ , sizeof (session_fifo_event_t), 0 /* consumer pid */ , 0 /* (do not) signal when queue non-empty */ ); svm_pop_heap (oldheap); /* If a server, allocate session manager */ if (type == APP_SERVER) { pool_get (smm->session_managers, sm); memset (sm, 0, sizeof (*sm)); app->session_manager_index = sm - smm->session_managers; } else if (type == APP_CLIENT) { /* Allocate connect session manager if needed */ if (smm->connect_manager_index[sst] == INVALID_INDEX) connects_session_manager_init (smm, sst); app->session_manager_index = smm->connect_manager_index[sst]; } app->mode = type; app->index = application_get_index (app); app->session_type = sst; app->api_client_index = api_client_index; app->flags = flags; app->cb_fns = *cb_fns; /* Add app to lookup by api_client_index table */ application_table_add (app); return app; } application_t * application_get (u32 index) { return pool_elt_at_index (app_pool, index); } u32 application_get_index (application_t * app) { return app - app_pool; } int application_server_init (application_t * server, u32 segment_size, u32 add_segment_size, u32 rx_fifo_size, u32 tx_fifo_size, u8 ** segment_name) { session_manager_main_t *smm = vnet_get_session_manager_main (); session_manager_t *sm; int rv; sm = session_manager_get (server->session_manager_index); /* Add first segment */ if ((rv = session_manager_add_first_segment (smm, sm, segment_size, segment_name))) { return rv; } /* Setup session manager */ sm->add_segment_size = add_segment_size; sm->rx_fifo_size = rx_fifo_size; sm->tx_fifo_size = tx_fifo_size; sm->add_segment = sm->add_segment_size != 0; return 0; } u8 * format_application_server (u8 * s, va_list * args) { application_t *srv = va_arg (*args, application_t *); int verbose = va_arg (*args, int); vl_api_registration_t *regp; stream_session_t *listener; u8 *server_name, *str, *seg_name; u32 segment_size; if (srv == 0) { if (verbose) s = format (s, "%-40s%-20s%-15s%-15s%-10s", "Connection", "Server", "Segment", "API Client", "Cookie"); else s = format (s, "%-40s%-20s", "Connection", "Server"); return s; } regp = vl_api_client_index_to_registration (srv->api_client_index); if (!regp) server_name = format (0, "%s%c", regp->name, 0); else server_name = regp->name; listener = stream_session_listener_get (srv->session_type, srv->session_index); str = format (0, "%U", format_stream_session, listener, verbose); session_manager_get_segment_info (listener->server_segment_index, &seg_name, &segment_size); if (verbose) { s = format (s, "%-40s%-20s%-20s%-10d%-10d", str, server_name, seg_name, srv->api_client_index, srv->accept_cookie); } else s = format (s, "%-40s%-20s", str, server_name); return s; } u8 * format_application_client (u8 * s, va_list * args) { application_t *client = va_arg (*args, application_t *); int verbose = va_arg (*args, int); stream_session_t *session; u8 *str, *seg_name; u32 segment_size; if (client == 0) { if (verbose) s = format (s, "%-40s%-20s%-10s", "Connection", "Segment", "API Client"); else s = format (s, "%-40s", "Connection"); return s; } session = stream_session_get (client->session_index, client->thread_index); str = format (0, "%U", format_stream_session, session, verbose); session_manager_get_segment_info (session->server_segment_index, &seg_name, &segment_size); if (verbose) { s = format (s, "%-40s%-20s%-10d%", str, seg_name, client->api_client_index); } else s = format (s, "%-40s", str); return s; } static clib_error_t * show_app_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { application_t *app; int do_server = 0; int do_client = 0; int verbose = 0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "server")) do_server = 1; else if (unformat (input, "client")) do_client = 1; else if (unformat (input, "verbose")) verbose = 1; else break; } if (do_server) { if (pool_elts (app_pool)) { vlib_cli_output (vm, "%U", format_application_server, 0 /* header */ , verbose); /* *INDENT-OFF* */ pool_foreach (app, app_pool, ({ if (app->mode == APP_SERVER) vlib_cli_output (vm, "%U", format_application_server, app, verbose); })); /* *INDENT-ON* */ } else vlib_cli_output (vm, "No active server bindings"); } if (do_client) { if (pool_elts (app_pool)) { vlib_cli_output (vm, "%U", format_application_client, 0 /* header */ , verbose); /* *INDENT-OFF* */ pool_foreach (app, app_pool, ({ if (app->mode == APP_CLIENT) vlib_cli_output (vm, "%U", format_application_client, app, verbose); })); /* *INDENT-ON* */ } else vlib_cli_output (vm, "No active server bindings"); } return 0; } VLIB_CLI_COMMAND (show_app_command, static) = { .path = "show app",.short_help = "show app [server|client] [verbose]",.function = show_app_command_fn,}; /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */