/* * 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. */ /** @file udp builtin server */ #include #include #include /** per-worker built-in server copy buffers */ u8 **copy_buffers; static int builtin_session_create_callback (stream_session_t * s) { /* Simple version: declare session ready-to-go... */ s->session_state = SESSION_STATE_READY; return 0; } static void builtin_session_disconnect_callback (stream_session_t * s) { stream_session_disconnect (s); } static int builtin_server_rx_callback (stream_session_t * s) { svm_fifo_t *rx_fifo, *tx_fifo; u32 this_transfer, max_deq, max_enq; int actual_transfer; u8 *my_copy_buffer; session_fifo_event_t evt; unix_shared_memory_queue_t *q; my_copy_buffer = copy_buffers[s->thread_index]; rx_fifo = s->server_rx_fifo; tx_fifo = s->server_tx_fifo; max_deq = svm_fifo_max_dequeue (rx_fifo); max_enq = svm_fifo_max_enqueue (tx_fifo); this_transfer = max_enq < max_deq ? max_enq : max_deq; vec_validate (my_copy_buffer, this_transfer - 1); _vec_len (my_copy_buffer) = this_transfer; actual_transfer = svm_fifo_dequeue_nowait (rx_fifo, this_transfer, my_copy_buffer); ASSERT (actual_transfer == this_transfer); actual_transfer = svm_fifo_enqueue_nowait (tx_fifo, this_transfer, my_copy_buffer); ASSERT (actual_transfer == this_transfer); copy_buffers[s->thread_index] = my_copy_buffer; if (svm_fifo_set_event (tx_fifo)) { /* Fabricate TX event, send to ourselves */ evt.fifo = tx_fifo; evt.event_type = FIFO_EVENT_APP_TX; evt.event_id = 0; q = session_manager_get_vpp_event_queue (s->thread_index); unix_shared_memory_queue_add (q, (u8 *) & evt, 0 /* do wait for mutex */ ); } return 0; } /* *INDENT-OFF* */ static session_cb_vft_t builtin_server = { .session_accept_callback = builtin_session_create_callback, .session_disconnect_callback = builtin_session_disconnect_callback, .builtin_server_rx_callback = builtin_server_rx_callback }; /* *INDENT-ON* */ static int attach_builtin_uri_server () { vnet_app_attach_args_t _a, *a = &_a; u8 segment_name[128]; u32 segment_name_length; u64 options[16]; segment_name_length = ARRAY_LEN (segment_name); memset (a, 0, sizeof (*a)); memset (options, 0, sizeof (options)); a->api_client_index = ~0; a->segment_name = segment_name; a->segment_name_length = segment_name_length; a->session_cb_vft = &builtin_server; options[SESSION_OPTIONS_ACCEPT_COOKIE] = 0x12345678; options[SESSION_OPTIONS_SEGMENT_SIZE] = (2 << 30); /*$$$$ config / arg */ options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_BUILTIN_APP; options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = 1024; a->options = options; return vnet_application_attach (a); } static int bind_builtin_uri_server (u8 * uri) { vnet_bind_args_t _a, *a = &_a; int rv; rv = attach_builtin_uri_server (); if (rv) return rv; memset (a, 0, sizeof (*a)); a->uri = (char *) uri; a->app_index = ~0; /* built-in server */ rv = vnet_bind_uri (a); return rv; } static int unbind_builtin_uri_server (u8 * uri) { vnet_unbind_args_t _a, *a = &_a; a->app_index = ~0; a->uri = (char *) uri; return vnet_unbind_uri (a); } static clib_error_t * builtin_server_init (vlib_main_t * vm) { vlib_thread_main_t *vtm = vlib_get_thread_main (); u32 num_threads; num_threads = 1 /* main thread */ + vtm->n_threads; vec_validate (copy_buffers, num_threads - 1); return 0; } VLIB_INIT_FUNCTION (builtin_server_init); static clib_error_t * builtin_uri_bind_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { u8 *uri = 0; int rv; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "uri %s", &uri)) ; else break; } if (uri == 0) return clib_error_return (0, "uri to bind not specified..."); rv = bind_builtin_uri_server (uri); vec_free (uri); switch (rv) { case 0: break; default: return clib_error_return (0, "bind_uri_server returned %d", rv); break; } return 0; } /* *INDENT-OFF* */ VLIB_CLI_COMMAND (builtin_uri_bind_command, static) = { .path = "builtin uri bind", .short_help = "builtin uri bind", .function = builtin_uri_bind_command_fn, }; /* *INDENT-ON* */ static clib_error_t * builtin_uri_unbind_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { u8 *uri = 0; int rv; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "uri %s", &uri)) ; else break; } if (uri == 0) return clib_error_return (0, "uri to unbind not specified..."); rv = unbind_builtin_uri_server (uri); vec_free (uri); switch (rv) { case 0: break; default: return clib_error_return (0, "unbind_uri_server returned %d", rv); break; } return 0; } /* *INDENT-OFF* */ VLIB_CLI_COMMAND (builtin_uri_unbind_command, static) = { .path = "builtin uri unbind", .short_help = "builtin uri unbind", .function = builtin_uri_unbind_command_fn, }; /* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */