From 543852a46ce107243ed92254bd88b87ca82bbd0b Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Thu, 3 Aug 2017 02:11:34 -0400 Subject: Add VPP Communications Library (VCL) - VCL library - client/server test application - test script (make test integration tbd) - gdb command file templates - vppcom test config file Change-Id: I21eab7aa09b4e5dc3412acf5c2eab07415c2fc0f Signed-off-by: Dave Wallace --- src/uri/vppcom.c | 2453 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2453 insertions(+) create mode 100644 src/uri/vppcom.c (limited to 'src/uri/vppcom.c') diff --git a/src/uri/vppcom.c b/src/uri/vppcom.c new file mode 100644 index 00000000..44208cc0 --- /dev/null +++ b/src/uri/vppcom.c @@ -0,0 +1,2453 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +/* declare message handlers for each api */ + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +#if (CLIB_DEBUG > 0) +/* Set VPPCOM_DEBUG 2 for connection debug, 3 for read/write debug output */ +#define VPPCOM_DEBUG 1 +#else +#define VPPCOM_DEBUG 0 +#endif + +/* + * VPPCOM Private definitions and functions. + */ +typedef enum +{ + STATE_APP_START, + STATE_APP_CONN_VPP, + STATE_APP_ENABLED, + STATE_APP_ATTACHED, +} app_state_t; + +typedef enum +{ + STATE_START, + STATE_CONNECT, + STATE_LISTEN, + STATE_ACCEPT, + STATE_DISCONNECT, + STATE_FAILED +} session_state_t; + +typedef struct +{ + volatile session_state_t state; + + svm_fifo_t *server_rx_fifo; + svm_fifo_t *server_tx_fifo; + u32 sm_seg_index; + u64 vpp_session_handle; + unix_shared_memory_queue_t *event_queue; + + /* Socket configuration state */ + u8 is_server; + u8 is_listen; + u8 is_cut_thru; + u8 is_nonblocking; + u32 vrf; + u8 is_ip4; + u8 ip[16]; + u16 port; + u8 proto; + u64 client_queue_address; + u64 options[16]; +} session_t; + +typedef struct vppcom_cfg_t_ +{ + u64 heapsize; + u64 segment_baseva; + u32 segment_size; + u32 add_segment_size; + u32 preallocated_fifo_pairs; + u32 rx_fifo_size; + u32 tx_fifo_size; + u32 event_queue_size; + u32 listen_queue_size; + f64 app_timeout; + f64 session_timeout; + f64 accept_timeout; +} vppcom_cfg_t; + +typedef struct vppcom_main_t_ +{ + u8 init; + u32 *client_session_index_fifo; + volatile u32 bind_session_index; + u32 tx_event_id; + int main_cpu; + + /* vpe input queue */ + unix_shared_memory_queue_t *vl_input_queue; + + /* API client handle */ + u32 my_client_index; + + /* Session pool */ + clib_spinlock_t sessions_lockp; + session_t *sessions; + + /* Hash table for disconnect processing */ + uword *session_index_by_vpp_handles; + + /* Select bitmaps */ + clib_bitmap_t *rd_bitmap; + clib_bitmap_t *wr_bitmap; + clib_bitmap_t *ex_bitmap; + + /* Our event queue */ + unix_shared_memory_queue_t *app_event_queue; + + /* unique segment name counter */ + u32 unique_segment_index; + + pid_t my_pid; + + /* For deadman timers */ + clib_time_t clib_time; + + /* State of the connection, shared between msg RX thread and main thread */ + volatile app_state_t app_state; + + vppcom_cfg_t cfg; + + /* VNET_API_ERROR_FOO -> "Foo" hash table */ + uword *error_string_by_error_number; +} vppcom_main_t; + +vppcom_main_t vppcom_main = {.my_client_index = ~0 }; + +static const char * +vppcom_app_state_str (app_state_t state) +{ + char *st; + + switch (state) + { + case STATE_APP_START: + st = "STATE_APP_START"; + break; + + case STATE_APP_CONN_VPP: + st = "STATE_APP_CONN_VPP"; + break; + + case STATE_APP_ENABLED: + st = "STATE_APP_ENABLED"; + break; + + case STATE_APP_ATTACHED: + st = "STATE_APP_ATTACHED"; + break; + + default: + st = "UNKNOWN_APP_STATE"; + break; + } + + return st; +} + +static const char * +vppcom_session_state_str (session_state_t state) +{ + char *st; + + switch (state) + { + case STATE_START: + st = "STATE_START"; + break; + + case STATE_CONNECT: + st = "STATE_CONNECT"; + break; + + case STATE_LISTEN: + st = "STATE_LISTEN"; + break; + + case STATE_ACCEPT: + st = "STATE_ACCEPT"; + break; + + case STATE_DISCONNECT: + st = "STATE_DISCONNECT"; + break; + + case STATE_FAILED: + st = "STATE_FAILED"; + break; + + default: + st = "UNKNOWN_STATE"; + break; + } + + return st; +} + +/* + * VPPCOM Utility Functions + */ +static inline int +vppcom_session_at_index (u32 session_index, session_t * volatile *sess) +{ + vppcom_main_t *vcm = &vppcom_main; + + /* Assumes that caller has acquired spinlock: vcm->sessions_lockp */ + if (PREDICT_FALSE ((session_index == ~0) || + pool_is_free_index (vcm->sessions, session_index))) + { + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, session_index); + return VPPCOM_EBADFD; + } + *sess = pool_elt_at_index (vcm->sessions, session_index); + return VPPCOM_OK; +} + +static int +vppcom_connect_to_vpp (char *app_name) +{ + api_main_t *am = &api_main; + vppcom_main_t *vcm = &vppcom_main; + + if (VPPCOM_DEBUG > 0) + printf ("\nConnecting to VPP api..."); + if (vl_client_connect_to_vlib ("/vpe-api", app_name, 32) < 0) + { + clib_warning ("[%d] connect to vpp (%s) failed!", + vcm->my_pid, app_name); + return VPPCOM_ECONNREFUSED; + } + + vcm->vl_input_queue = am->shmem_hdr->vl_input_queue; + vcm->my_client_index = am->my_client_index; + if (VPPCOM_DEBUG > 0) + printf (" connected!\n"); + + vcm->app_state = STATE_APP_CONN_VPP; + return VPPCOM_OK; +} + +static u8 * +format_api_error (u8 * s, va_list * args) +{ + vppcom_main_t *vcm = &vppcom_main; + i32 error = va_arg (*args, u32); + uword *p; + + p = hash_get (vcm->error_string_by_error_number, -error); + + if (p) + s = format (s, "%s (%d)", p[0], error); + else + s = format (s, "%d", error); + return s; +} + +static void +vppcom_init_error_string_table (void) +{ + vppcom_main_t *vcm = &vppcom_main; + + vcm->error_string_by_error_number = hash_create (0, sizeof (uword)); + +#define _(n,v,s) hash_set (vcm->error_string_by_error_number, -v, s); + foreach_vnet_api_error; +#undef _ + + hash_set (vcm->error_string_by_error_number, 99, "Misc"); +} + +static inline int +vppcom_wait_for_app_state_change (app_state_t app_state) +{ + vppcom_main_t *vcm = &vppcom_main; + f64 timeout = clib_time_now (&vcm->clib_time) + vcm->cfg.app_timeout; + + while (clib_time_now (&vcm->clib_time) < timeout) + { + if (vcm->app_state == app_state) + return VPPCOM_OK; + } + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] timeout waiting for state %s (%d)", vcm->my_pid, + vppcom_app_state_str (app_state), app_state); + return VPPCOM_ETIMEDOUT; +} + +static inline int +vppcom_wait_for_session_state_change (u32 session_index, + session_state_t state, + f64 wait_for_time) +{ + vppcom_main_t *vcm = &vppcom_main; + f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time; + session_t *volatile session; + int rv; + + do + { + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (session_index, &session); + if (PREDICT_FALSE (rv)) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + return rv; + } + if (session->state == state) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + return VPPCOM_OK; + } + clib_spinlock_unlock (&vcm->sessions_lockp); + } + while (clib_time_now (&vcm->clib_time) < timeout); + + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] timeout waiting for state %s (%d)", vcm->my_pid, + vppcom_session_state_str (state), state); + return VPPCOM_ETIMEDOUT; +} + +static inline int +vppcom_wait_for_client_session_index (f64 wait_for_time) +{ + vppcom_main_t *vcm = &vppcom_main; + f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time; + + do + { + if (clib_fifo_elts (vcm->client_session_index_fifo)) + return VPPCOM_OK; + } + while (clib_time_now (&vcm->clib_time) < timeout); + + if (wait_for_time == 0) + return VPPCOM_EAGAIN; + + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] timeout waiting for client_session_index", + vcm->my_pid); + return VPPCOM_ETIMEDOUT; +} + +/* + * VPP-API message functions + */ +static void +vppcom_send_session_enable_disable (u8 is_enable) +{ + vppcom_main_t *vcm = &vppcom_main; + vl_api_session_enable_disable_t *bmp; + bmp = vl_msg_api_alloc (sizeof (*bmp)); + memset (bmp, 0, sizeof (*bmp)); + + bmp->_vl_msg_id = ntohs (VL_API_SESSION_ENABLE_DISABLE); + bmp->client_index = vcm->my_client_index; + bmp->context = htonl (0xfeedface); + bmp->is_enable = is_enable; + vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp); +} + +static int +vppcom_app_session_enable (void) +{ + vppcom_main_t *vcm = &vppcom_main; + int rv; + + if (vcm->app_state != STATE_APP_ENABLED) + { + vppcom_send_session_enable_disable (1 /* is_enabled == TRUE */ ); + rv = vppcom_wait_for_app_state_change (STATE_APP_ENABLED); + if (PREDICT_FALSE (rv)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] Session enable timed out, rv = %s (%d)", + vcm->my_pid, vppcom_retval_str (rv), rv); + return rv; + } + } + return VPPCOM_OK; +} + +static void + vl_api_session_enable_disable_reply_t_handler + (vl_api_session_enable_disable_reply_t * mp) +{ + vppcom_main_t *vcm = &vppcom_main; + + if (mp->retval) + { + clib_warning ("[%d] session_enable_disable failed: %U", vcm->my_pid, + format_api_error, ntohl (mp->retval)); + } + else + vcm->app_state = STATE_APP_ENABLED; +} + +static void +vppcom_app_send_attach (void) +{ + vppcom_main_t *vcm = &vppcom_main; + vl_api_application_attach_t *bmp; + bmp = vl_msg_api_alloc (sizeof (*bmp)); + memset (bmp, 0, sizeof (*bmp)); + + bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_ATTACH); + bmp->client_index = vcm->my_client_index; + bmp->context = htonl (0xfeedface); + bmp->options[APP_OPTIONS_FLAGS] = + APP_OPTIONS_FLAGS_USE_FIFO | APP_OPTIONS_FLAGS_ADD_SEGMENT; + bmp->options[SESSION_OPTIONS_SEGMENT_SIZE] = vcm->cfg.segment_size; + bmp->options[SESSION_OPTIONS_ADD_SEGMENT_SIZE] = vcm->cfg.add_segment_size; + bmp->options[SESSION_OPTIONS_RX_FIFO_SIZE] = vcm->cfg.rx_fifo_size; + bmp->options[SESSION_OPTIONS_TX_FIFO_SIZE] = vcm->cfg.tx_fifo_size; + vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp); +} + +static int +vppcom_app_attach (void) +{ + vppcom_main_t *vcm = &vppcom_main; + int rv; + + vppcom_app_send_attach (); + rv = vppcom_wait_for_app_state_change (STATE_APP_ATTACHED); + if (PREDICT_FALSE (rv)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] application attach timed out, rv = %s (%d)", + vcm->my_pid, vppcom_retval_str (rv), rv); + return rv; + } + return VPPCOM_OK; +} + +static void +vppcom_app_detach (void) +{ + vppcom_main_t *vcm = &vppcom_main; + vl_api_application_detach_t *bmp; + bmp = vl_msg_api_alloc (sizeof (*bmp)); + memset (bmp, 0, sizeof (*bmp)); + + bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_DETACH); + bmp->client_index = vcm->my_client_index; + bmp->context = htonl (0xfeedface); + vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp); +} + +static void +vl_api_application_attach_reply_t_handler (vl_api_application_attach_reply_t * + mp) +{ + vppcom_main_t *vcm = &vppcom_main; + static svm_fifo_segment_create_args_t _a; + svm_fifo_segment_create_args_t *a = &_a; + int rv; + + memset (a, 0, sizeof (*a)); + if (mp->retval) + { + clib_warning ("[%d] attach failed: %U", vcm->my_pid, + format_api_error, ntohl (mp->retval)); + return; + } + + if (mp->segment_name_length == 0) + { + clib_warning ("[%d] segment_name_length zero", vcm->my_pid); + return; + } + + a->segment_name = (char *) mp->segment_name; + a->segment_size = mp->segment_size; + + ASSERT (mp->app_event_queue_address); + + /* Attach to the segment vpp created */ + rv = svm_fifo_segment_attach (a); + vec_reset_length (a->new_segment_indices); + if (PREDICT_FALSE (rv)) + { + clib_warning ("[%d] svm_fifo_segment_attach ('%s') failed", vcm->my_pid, + mp->segment_name); + return; + } + + vcm->app_event_queue = + uword_to_pointer (mp->app_event_queue_address, + unix_shared_memory_queue_t *); + + vcm->app_state = STATE_APP_ATTACHED; +} + +static void +vl_api_application_detach_reply_t_handler (vl_api_application_detach_reply_t * + mp) +{ + vppcom_main_t *vcm = &vppcom_main; + + if (mp->retval) + clib_warning ("[%d] detach failed: %U", vcm->my_pid, format_api_error, + ntohl (mp->retval)); + + vcm->app_state = STATE_APP_ENABLED; +} + +static void +vl_api_disconnect_session_reply_t_handler (vl_api_disconnect_session_reply_t * + mp) +{ + vppcom_main_t *vcm = &vppcom_main; + uword *p; + + p = hash_get (vcm->session_index_by_vpp_handles, mp->handle); + if (p) + { + session_t *session = 0; + int rv; + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (p[0], &session); + if (PREDICT_FALSE (rv)) + { + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, p[0]); + } + hash_unset (vcm->session_index_by_vpp_handles, mp->handle); + session->state = STATE_DISCONNECT; + clib_spinlock_unlock (&vcm->sessions_lockp); + } + else + { + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] couldn't find session key %llx", vcm->my_pid, + mp->handle); + } + + if (mp->retval) + clib_warning ("[%d] disconnect_session failed: %U", vcm->my_pid, + format_api_error, ntohl (mp->retval)); +} + +static void +vl_api_map_another_segment_t_handler (vl_api_map_another_segment_t * mp) +{ + vppcom_main_t *vcm = &vppcom_main; + static svm_fifo_segment_create_args_t _a; + svm_fifo_segment_create_args_t *a = &_a; + int rv; + + memset (a, 0, sizeof (*a)); + a->segment_name = (char *) mp->segment_name; + a->segment_size = mp->segment_size; + /* Attach to the segment vpp created */ + rv = svm_fifo_segment_attach (a); + vec_reset_length (a->new_segment_indices); + if (PREDICT_FALSE (rv)) + { + clib_warning ("[%d] svm_fifo_segment_attach ('%s') failed", + vcm->my_pid, mp->segment_name); + return; + } + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] mapped new segment '%s' size %d", vcm->my_pid, + mp->segment_name, mp->segment_size); +} + +static void +vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp) +{ + vppcom_main_t *vcm = &vppcom_main; + session_t *session = 0; + vl_api_disconnect_session_reply_t *rmp; + uword *p; + int rv = 0; + + p = hash_get (vcm->session_index_by_vpp_handles, mp->handle); + if (p) + { + int rval; + clib_spinlock_lock (&vcm->sessions_lockp); + rval = vppcom_session_at_index (p[0], &session); + if (PREDICT_FALSE (rval)) + { + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, p[0]); + } + else + pool_put (vcm->sessions, session); + clib_spinlock_unlock (&vcm->sessions_lockp); + hash_unset (vcm->session_index_by_vpp_handles, mp->handle); + } + else + { + clib_warning ("[%d] couldn't find session key %llx", vcm->my_pid, + mp->handle); + rv = -11; + } + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + memset (rmp, 0, sizeof (*rmp)); + + rmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION_REPLY); + rmp->retval = htonl (rv); + rmp->handle = mp->handle; + vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp); +} + +static void +vl_api_reset_session_t_handler (vl_api_reset_session_t * mp) +{ + vppcom_main_t *vcm = &vppcom_main; + session_t *session = 0; + vl_api_reset_session_reply_t *rmp; + uword *p; + int rv = 0; + + p = hash_get (vcm->session_index_by_vpp_handles, mp->handle); + if (p) + { + int rval; + clib_spinlock_lock (&vcm->sessions_lockp); + rval = vppcom_session_at_index (p[0], &session); + if (PREDICT_FALSE (rval)) + { + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, p[0]); + } + else + pool_put (vcm->sessions, session); + clib_spinlock_unlock (&vcm->sessions_lockp); + hash_unset (vcm->session_index_by_vpp_handles, mp->handle); + } + else + { + clib_warning ("[%d] couldn't find session key %llx", vcm->my_pid, + mp->handle); + rv = -11; + } + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + memset (rmp, 0, sizeof (*rmp)); + rmp->_vl_msg_id = ntohs (VL_API_RESET_SESSION_REPLY); + rmp->retval = htonl (rv); + rmp->handle = mp->handle; + vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp); +} + +static void +vl_api_connect_sock_reply_t_handler (vl_api_connect_sock_reply_t * mp) +{ + vppcom_main_t *vcm = &vppcom_main; + session_t *session; + u32 session_index; + svm_fifo_t *rx_fifo, *tx_fifo; + u8 is_cut_thru = 0; + int rv; + + if (mp->retval) + { + clib_warning ("[%d] connect failed: %U", vcm->my_pid, format_api_error, + ntohl (mp->retval)); + return; + } + + session_index = ntohl (mp->app_connect); + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] app_connect = %d 0x%08x", vcm->my_pid, + session_index, session_index); + + clib_spinlock_lock (&vcm->sessions_lockp); + if (pool_is_free_index (vcm->sessions, session_index)) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] invalid session, sid %d is closed!", + vcm->my_pid, session_index); + return; + } + + /* We've been redirected */ + if (mp->segment_name_length > 0) + { + static svm_fifo_segment_create_args_t _a; + svm_fifo_segment_create_args_t *a = &_a; + + is_cut_thru = 1; + memset (a, 0, sizeof (*a)); + a->segment_name = (char *) mp->segment_name; + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] cut-thru segment: %s", vcm->my_pid, + a->segment_name); + rv = svm_fifo_segment_attach (a); + vec_reset_length (a->new_segment_indices); + if (PREDICT_FALSE (rv)) + { + clib_warning ("[%d] sm_fifo_segment_attach ('%s') failed", + vcm->my_pid, a->segment_name); + return; + } + } + + /* + * Setup session + */ + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] client sid %d", vcm->my_pid, session_index); + + session = pool_elt_at_index (vcm->sessions, session_index); + session->is_cut_thru = is_cut_thru; + session->event_queue = uword_to_pointer (mp->vpp_event_queue_address, + unix_shared_memory_queue_t *); + + rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *); + rx_fifo->client_session_index = session_index; + tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *); + tx_fifo->client_session_index = session_index; + + session->server_rx_fifo = rx_fifo; + session->server_tx_fifo = tx_fifo; + session->vpp_session_handle = mp->handle; + session->state = STATE_CONNECT; + + /* Add it to lookup table */ + hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index); + clib_spinlock_unlock (&vcm->sessions_lockp); +} + +static void +vppcom_send_connect_sock (session_t * session, u32 session_index) +{ + vppcom_main_t *vcm = &vppcom_main; + vl_api_connect_sock_t *cmp; + + /* Assumes caller as acquired the spinlock: vcm->sessions_lockp */ + session->is_server = 0; + cmp = vl_msg_api_alloc (sizeof (*cmp)); + memset (cmp, 0, sizeof (*cmp)); + cmp->_vl_msg_id = ntohs (VL_API_CONNECT_SOCK); + cmp->client_index = vcm->my_client_index; + cmp->context = htonl (0xfeedface); + cmp->app_connect = session_index; + + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] session_index = %d 0x%08x, app_connect = %d 0x%08x", + vcm->my_pid, session_index, session_index, + cmp->app_connect, cmp->app_connect); + + cmp->vrf = session->vrf; + cmp->is_ip4 = session->is_ip4; + clib_memcpy (cmp->ip, session->ip, (session->is_ip4 ? + sizeof (ip4_address_t) : + sizeof (ip6_address_t))); + cmp->port = session->port; + cmp->proto = session->proto; + clib_memcpy (cmp->options, session->options, sizeof (cmp->options)); + vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & cmp); +} + +static int +vppcom_send_disconnect (u32 session_index) +{ + vppcom_main_t *vcm = &vppcom_main; + vl_api_disconnect_session_t *dmp; + session_t *session = 0; + int rv; + + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (session_index, &session); + if (PREDICT_FALSE (rv)) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, session_index); + return rv; + } + + dmp = vl_msg_api_alloc (sizeof (*dmp)); + memset (dmp, 0, sizeof (*dmp)); + dmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION); + dmp->client_index = vcm->my_client_index; + dmp->handle = session->vpp_session_handle; + clib_spinlock_unlock (&vcm->sessions_lockp); + vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & dmp); + return VPPCOM_OK; +} + +static void +vl_api_bind_sock_reply_t_handler (vl_api_bind_sock_reply_t * mp) +{ + vppcom_main_t *vcm = &vppcom_main; + session_t *session = 0; + int rv; + + if (mp->retval) + clib_warning ("[%d] bind failed: %U", vcm->my_pid, format_api_error, + ntohl (mp->retval)); + + ASSERT (vcm->bind_session_index != ~0); + + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (vcm->bind_session_index, &session); + if (rv == VPPCOM_OK) + { + session->vpp_session_handle = mp->handle; + hash_set (vcm->session_index_by_vpp_handles, mp->handle, + vcm->bind_session_index); + session->state = mp->retval ? STATE_FAILED : STATE_LISTEN; + vcm->bind_session_index = ~0; + } + clib_spinlock_unlock (&vcm->sessions_lockp); +} + +static void +vl_api_unbind_sock_reply_t_handler (vl_api_unbind_sock_reply_t * mp) +{ + vppcom_main_t *vcm = &vppcom_main; + session_t *session = 0; + int rv; + + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (vcm->bind_session_index, &session); + if (PREDICT_FALSE (rv)) + { + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, vcm->bind_session_index); + } + + if (mp->retval) + clib_warning ("[%d] unbind failed: %U", vcm->my_pid, format_api_error, + ntohl (mp->retval)); + + vcm->bind_session_index = ~0; + session->state = STATE_START; + clib_spinlock_unlock (&vcm->sessions_lockp); +} + +u8 * +format_ip4_address (u8 * s, va_list * args) +{ + u8 *a = va_arg (*args, u8 *); + return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); +} + +u8 * +format_ip6_address (u8 * s, va_list * args) +{ + ip6_address_t *a = va_arg (*args, ip6_address_t *); + u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon; + + i_max_n_zero = ARRAY_LEN (a->as_u16); + max_n_zeros = 0; + i_first_zero = i_max_n_zero; + n_zeros = 0; + for (i = 0; i < ARRAY_LEN (a->as_u16); i++) + { + u32 is_zero = a->as_u16[i] == 0; + if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16)) + { + i_first_zero = i; + n_zeros = 0; + } + n_zeros += is_zero; + if ((!is_zero && n_zeros > max_n_zeros) + || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros)) + { + i_max_n_zero = i_first_zero; + max_n_zeros = n_zeros; + i_first_zero = ARRAY_LEN (a->as_u16); + n_zeros = 0; + } + } + + last_double_colon = 0; + for (i = 0; i < ARRAY_LEN (a->as_u16); i++) + { + if (i == i_max_n_zero && max_n_zeros > 1) + { + s = format (s, "::"); + i += max_n_zeros - 1; + last_double_colon = 1; + } + else + { + s = format (s, "%s%x", + (last_double_colon || i == 0) ? "" : ":", + clib_net_to_host_u16 (a->as_u16[i])); + last_double_colon = 0; + } + } + + return s; +} + +/* Format an IP46 address. */ +u8 * +format_ip46_address (u8 * s, va_list * args) +{ + ip46_address_t *ip46 = va_arg (*args, ip46_address_t *); + ip46_type_t type = va_arg (*args, ip46_type_t); + int is_ip4 = 1; + + switch (type) + { + case IP46_TYPE_ANY: + is_ip4 = ip46_address_is_ip4 (ip46); + break; + case IP46_TYPE_IP4: + is_ip4 = 1; + break; + case IP46_TYPE_IP6: + is_ip4 = 0; + break; + } + + return is_ip4 ? + format (s, "%U", format_ip4_address, &ip46->ip4) : + format (s, "%U", format_ip6_address, &ip46->ip6); +} + +static void +vl_api_accept_session_t_handler (vl_api_accept_session_t * mp) +{ + vppcom_main_t *vcm = &vppcom_main; + vl_api_accept_session_reply_t *rmp; + svm_fifo_t *rx_fifo, *tx_fifo; + session_t *session; + u32 session_index; + int rv = 0; + + if (!clib_fifo_free_elts (vcm->client_session_index_fifo)) + { + clib_warning ("[%d] client session queue is full!", vcm->my_pid); + rv = VNET_API_ERROR_QUEUE_FULL; + goto send_reply; + } + + if (VPPCOM_DEBUG > 1) + { + u8 *ip_str = format (0, "%U", format_ip46_address, &mp->ip, mp->is_ip4); + clib_warning ("[%d] accepted session from: %s:%d", vcm->my_pid, ip_str, + clib_net_to_host_u16 (mp->port)); + vec_free (ip_str); + } + + clib_spinlock_lock (&vcm->sessions_lockp); + /* Allocate local session and set it up */ + pool_get (vcm->sessions, session); + memset (session, 0, sizeof (*session)); + session_index = session - vcm->sessions; + + rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *); + rx_fifo->client_session_index = session_index; + tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *); + tx_fifo->client_session_index = session_index; + + session->server_rx_fifo = rx_fifo; + session->server_tx_fifo = tx_fifo; + session->event_queue = uword_to_pointer (mp->vpp_event_queue_address, + unix_shared_memory_queue_t *); + session->state = STATE_ACCEPT; + session->is_cut_thru = 0; + session->port = ntohs (mp->port); + session->is_ip4 = mp->is_ip4; + clib_memcpy (session->ip, mp->ip, (mp->is_ip4 ? + sizeof (ip4_address_t) : + sizeof (ip6_address_t))); + clib_spinlock_unlock (&vcm->sessions_lockp); + + /* Add it to lookup table */ + hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index); + + clib_fifo_add1 (vcm->client_session_index_fifo, session_index); + + /* + * Send accept reply to vpp + */ +send_reply: + rmp = vl_msg_api_alloc (sizeof (*rmp)); + memset (rmp, 0, sizeof (*rmp)); + rmp->_vl_msg_id = ntohs (VL_API_ACCEPT_SESSION_REPLY); + rmp->retval = htonl (rv); + rmp->handle = mp->handle; + vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp); +} + +/* + * Acting as server for redirected connect requests + */ +static void +vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp) +{ + static svm_fifo_segment_create_args_t _a; + svm_fifo_segment_create_args_t *a = &_a; + vppcom_main_t *vcm = &vppcom_main; + u32 session_index; + svm_fifo_segment_private_t *seg; + unix_shared_memory_queue_t *client_q; + vl_api_connect_sock_reply_t *rmp; + session_t *session = 0; + int rv = 0; + svm_fifo_t *rx_fifo; + svm_fifo_t *tx_fifo; + unix_shared_memory_queue_t *event_q = 0; + + if (!clib_fifo_free_elts (vcm->client_session_index_fifo)) + { + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] client session queue is full!", vcm->my_pid); + rv = VNET_API_ERROR_QUEUE_FULL; + goto send_reply; + } + + /* Create the segment */ + memset (a, 0, sizeof (*a)); + a->segment_name = (char *) format ((u8 *) a->segment_name, "%d:segment%d%c", + vcm->my_pid, vcm->unique_segment_index++, + 0); + a->segment_size = vcm->cfg.segment_size; + a->preallocated_fifo_pairs = vcm->cfg.preallocated_fifo_pairs; + a->rx_fifo_size = vcm->cfg.rx_fifo_size; + a->tx_fifo_size = vcm->cfg.tx_fifo_size; + + rv = svm_fifo_segment_create (a); + if (PREDICT_FALSE (rv)) + { + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] svm_fifo_segment_create ('%s') failed", + vcm->my_pid, a->segment_name); + vec_reset_length (a->new_segment_indices); + rv = VNET_API_ERROR_URI_FIFO_CREATE_FAILED; + goto send_reply; + } + + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] created segment '%s'", vcm->my_pid, a->segment_name); + + clib_spinlock_lock (&vcm->sessions_lockp); + pool_get (vcm->sessions, session); + memset (session, 0, sizeof (*session)); + session_index = session - vcm->sessions; + + session->sm_seg_index = a->new_segment_indices[0]; + vec_reset_length (a->new_segment_indices); + + seg = svm_fifo_get_segment (session->sm_seg_index); + rx_fifo = session->server_rx_fifo = + svm_fifo_segment_alloc_fifo (seg, vcm->cfg.rx_fifo_size, + FIFO_SEGMENT_RX_FREELIST); + if (PREDICT_FALSE (!session->server_rx_fifo)) + { + svm_fifo_segment_delete (seg); + clib_warning ("[%d] rx fifo alloc failed, size %ld (0x%lx)", + vcm->my_pid, vcm->cfg.rx_fifo_size, + vcm->cfg.rx_fifo_size); + rv = VNET_API_ERROR_URI_FIFO_CREATE_FAILED; + clib_spinlock_unlock (&vcm->sessions_lockp); + goto send_reply; + } + + tx_fifo = session->server_tx_fifo = + svm_fifo_segment_alloc_fifo (seg, vcm->cfg.tx_fifo_size, + FIFO_SEGMENT_TX_FREELIST); + if (PREDICT_FALSE (!session->server_tx_fifo)) + { + svm_fifo_segment_delete (seg); + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] tx fifo alloc failed, size %ld (0x%lx)", + vcm->my_pid, vcm->cfg.tx_fifo_size, + vcm->cfg.tx_fifo_size); + rv = VNET_API_ERROR_URI_FIFO_CREATE_FAILED; + clib_spinlock_unlock (&vcm->sessions_lockp); + goto send_reply; + } + + session->server_rx_fifo->master_session_index = session_index; + session->server_tx_fifo->master_session_index = session_index; + session->client_queue_address = mp->client_queue_address; + session->is_cut_thru = 1; + session->is_server = 1; + session->is_ip4 = mp->is_ip4; + session->port = mp->port; + { + void *oldheap; + ssvm_shared_header_t *sh = seg->ssvm.sh; + + ssvm_lock_non_recursive (sh, 1); + oldheap = ssvm_push_heap (sh); + event_q = session->event_queue = + unix_shared_memory_queue_init (vcm->cfg.event_queue_size, + sizeof (session_fifo_event_t), + vcm->my_pid, 0 /* signal not sent */ ); + ssvm_pop_heap (oldheap); + ssvm_unlock_non_recursive (sh); + } + clib_memcpy (session->ip, mp->ip, (mp->is_ip4 ? + sizeof (ip4_address_t) : + sizeof (ip6_address_t))); + session->state = STATE_ACCEPT; + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] Connected cut-thru to client: sid %d", + vcm->my_pid, session_index); + clib_spinlock_unlock (&vcm->sessions_lockp); + clib_fifo_add1 (vcm->client_session_index_fifo, session_index); + +send_reply: + rmp = vl_msg_api_alloc (sizeof (*rmp)); + memset (rmp, 0, sizeof (*rmp)); + + rmp->_vl_msg_id = ntohs (VL_API_CONNECT_SOCK_REPLY); + rmp->context = mp->context; + rmp->app_connect = htonl (mp->app_connect); + rmp->retval = htonl (rv); + rmp->segment_name_length = vec_len (a->segment_name); + clib_memcpy (rmp->segment_name, a->segment_name, vec_len (a->segment_name)); + vec_reset_length (a->segment_name); + + if (event_q) + { + rmp->vpp_event_queue_address = pointer_to_uword (event_q); + rmp->server_rx_fifo = pointer_to_uword (rx_fifo); + rmp->server_tx_fifo = pointer_to_uword (tx_fifo); + } + client_q = + uword_to_pointer (mp->client_queue_address, unix_shared_memory_queue_t *); + + ASSERT (client_q); + vl_msg_api_send_shmem (client_q, (u8 *) & rmp); +} + +static void +vppcom_send_bind_sock (session_t * session) +{ + vppcom_main_t *vcm = &vppcom_main; + vl_api_bind_sock_t *bmp; + + /* Assumes caller has acquired spinlock: vcm->sessions_lockp */ + session->is_server = 1; + bmp = vl_msg_api_alloc (sizeof (*bmp)); + memset (bmp, 0, sizeof (*bmp)); + + bmp->_vl_msg_id = ntohs (VL_API_BIND_SOCK); + bmp->client_index = vcm->my_client_index; + bmp->context = htonl (0xfeedface); + bmp->vrf = session->vrf; + bmp->is_ip4 = session->is_ip4; + clib_memcpy (bmp->ip, session->ip, (session->is_ip4 ? + sizeof (ip4_address_t) : + sizeof (ip6_address_t))); + bmp->port = session->port; + bmp->proto = session->proto; + clib_memcpy (bmp->options, session->options, sizeof (bmp->options)); + vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp); +} + +static void +vppcom_send_unbind_sock (u32 session_index) +{ + vppcom_main_t *vcm = &vppcom_main; + vl_api_unbind_sock_t *ump; + session_t *session = 0; + int rv; + + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (session_index, &session); + if (PREDICT_FALSE (rv)) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, session_index); + return; + } + + ump = vl_msg_api_alloc (sizeof (*ump)); + memset (ump, 0, sizeof (*ump)); + + ump->_vl_msg_id = ntohs (VL_API_UNBIND_SOCK); + ump->client_index = vcm->my_client_index; + ump->handle = session->vpp_session_handle; + clib_spinlock_unlock (&vcm->sessions_lockp); + vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & ump); +} + +static int +vppcom_session_unbind_cut_thru (session_t * session) +{ + svm_fifo_segment_main_t *sm = &svm_fifo_segment_main; + svm_fifo_segment_private_t *seg; + int rv = VPPCOM_OK; + + seg = vec_elt_at_index (sm->segments, session->sm_seg_index); + svm_fifo_segment_free_fifo (seg, session->server_rx_fifo, + FIFO_SEGMENT_RX_FREELIST); + svm_fifo_segment_free_fifo (seg, session->server_tx_fifo, + FIFO_SEGMENT_TX_FREELIST); + svm_fifo_segment_delete (seg); + + return rv; +} + +static int +vppcom_session_unbind (u32 session_index) +{ + vppcom_main_t *vcm = &vppcom_main; + int rv; + + clib_spinlock_lock (&vcm->sessions_lockp); + if (PREDICT_FALSE (pool_is_free_index (vcm->sessions, session_index))) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, session_index); + return VPPCOM_EBADFD; + } + clib_spinlock_unlock (&vcm->sessions_lockp); + + vcm->bind_session_index = session_index; + vppcom_send_unbind_sock (session_index); + rv = vppcom_wait_for_session_state_change (session_index, STATE_START, + vcm->cfg.session_timeout); + if (PREDICT_FALSE (rv)) + { + vcm->bind_session_index = ~0; + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] server unbind timed out, rv = %s (%d)", + vcm->my_pid, vppcom_retval_str (rv), rv); + return rv; + } + return VPPCOM_OK; +} + +static int +vppcom_session_disconnect (u32 session_index) +{ + vppcom_main_t *vcm = &vppcom_main; + int rv; + + rv = vppcom_send_disconnect (session_index); + if (PREDICT_FALSE (rv)) + return rv; + + rv = vppcom_wait_for_session_state_change (session_index, STATE_DISCONNECT, + vcm->cfg.session_timeout); + if (PREDICT_FALSE (rv)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] client disconnect timed out, rv = %s (%d)", + vcm->my_pid, vppcom_retval_str (rv), rv); + return rv; + } + + clib_spinlock_lock (&vcm->sessions_lockp); + pool_put_index (vcm->sessions, session_index); + clib_spinlock_unlock (&vcm->sessions_lockp); + return VPPCOM_OK; +} + +#define foreach_sock_msg \ +_(SESSION_ENABLE_DISABLE_REPLY, session_enable_disable_reply) \ +_(BIND_SOCK_REPLY, bind_sock_reply) \ +_(UNBIND_SOCK_REPLY, unbind_sock_reply) \ +_(ACCEPT_SESSION, accept_session) \ +_(CONNECT_SOCK, connect_sock) \ +_(CONNECT_SOCK_REPLY, connect_sock_reply) \ +_(DISCONNECT_SESSION, disconnect_session) \ +_(DISCONNECT_SESSION_REPLY, disconnect_session_reply) \ +_(RESET_SESSION, reset_session) \ +_(APPLICATION_ATTACH_REPLY, application_attach_reply) \ +_(APPLICATION_DETACH_REPLY, application_detach_reply) \ +_(MAP_ANOTHER_SEGMENT, map_another_segment) + +static void +vppcom_api_hookup (void) +{ +#define _(N,n) \ + vl_msg_api_set_handlers(VL_API_##N, #n, \ + vl_api_##n##_t_handler, \ + vl_noop_handler, \ + vl_api_##n##_t_endian, \ + vl_api_##n##_t_print, \ + sizeof(vl_api_##n##_t), 1); + foreach_sock_msg; +#undef _ +} + +static void +vppcom_cfg_init (vppcom_cfg_t * vcl_cfg) +{ + ASSERT (vcl_cfg); + + vcl_cfg->heapsize = (256ULL << 20); + vcl_cfg->segment_baseva = 0x200000000ULL; + vcl_cfg->segment_size = (256 << 20); + vcl_cfg->add_segment_size = (128 << 20); + vcl_cfg->preallocated_fifo_pairs = 8; + vcl_cfg->rx_fifo_size = (1 << 20); + vcl_cfg->tx_fifo_size = (1 << 20); + vcl_cfg->event_queue_size = 2048; + vcl_cfg->listen_queue_size = CLIB_CACHE_LINE_BYTES / sizeof (u32); + vcl_cfg->app_timeout = 10 * 60.0; + vcl_cfg->session_timeout = 10 * 60.0; + vcl_cfg->accept_timeout = 60.0; +} + +static void +vppcom_cfg_heapsize (char *conf_fname) +{ + vppcom_main_t *vcm = &vppcom_main; + vppcom_cfg_t *vcl_cfg = &vcm->cfg; + FILE *fp; + char inbuf[4096]; + int argc = 1; + char **argv = NULL; + char *arg = NULL; + char *p; + int i; + u8 *sizep; + u32 size; + + fp = fopen (conf_fname, "r"); + if (fp == NULL) + { + if (VPPCOM_DEBUG > 0) + fprintf (stderr, "open configuration file '%s' failed\n", conf_fname); + goto defaulted; + } + argv = calloc (1, sizeof (char *)); + if (argv == NULL) + goto defaulted; + + while (1) + { + if (fgets (inbuf, 4096, fp) == 0) + break; + p = strtok (inbuf, " \t\n"); + while (p != NULL) + { + if (*p == '#') + break; + argc++; + char **tmp = realloc (argv, argc * sizeof (char *)); + if (tmp == NULL) + { + fclose (fp); + goto defaulted; + } + argv = tmp; + arg = strndup (p, 1024); + if (arg == NULL) + { + fclose (fp); + goto defaulted; + } + argv[argc - 1] = arg; + p = strtok (NULL, " \t\n"); + } + } + + fclose (fp); + + char **tmp = realloc (argv, (argc + 1) * sizeof (char *)); + if (tmp == NULL) + goto defaulted; + argv = tmp; + argv[argc] = NULL; + + /* + * Look for and parse the "heapsize" config parameter. + * Manual since none of the clib infra has been bootstrapped yet. + * + * Format: heapsize [mM][gG] + */ + + for (i = 1; i < (argc - 1); i++) + { + if (!strncmp (argv[i], "heapsize", 8)) + { + sizep = (u8 *) argv[i + 1]; + size = 0; + while (*sizep >= '0' && *sizep <= '9') + { + size *= 10; + size += *sizep++ - '0'; + } + if (size == 0) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] parse error '%s %s', " + "using default heapsize %lld (0x%llx)", + vcm->my_pid, argv[i], argv[i + 1], + vcl_cfg->heapsize, vcl_cfg->heapsize); + goto defaulted; + } + + if (*sizep == 'g' || *sizep == 'G') + vcl_cfg->heapsize = size << 30; + else if (*sizep == 'm' || *sizep == 'M') + vcl_cfg->heapsize = size << 20; + else + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] parse error '%s %s', " + "using default heapsize %lld (0x%llx)", + vcm->my_pid, argv[i], argv[i + 1], + vcl_cfg->heapsize, vcl_cfg->heapsize); + goto defaulted; + } + } + } + +defaulted: + if (!clib_mem_init (0, vcl_cfg->heapsize)) + clib_warning ("[%d] vppcom heap allocation failure!", vcm->my_pid); + else if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] allocated vppcom heapsize %lld (0x%llx)", + vcm->my_pid, vcl_cfg->heapsize, vcl_cfg->heapsize); +} + +static void +vppcom_cfg_read (char *conf_fname) +{ + vppcom_main_t *vcm = &vppcom_main; + vppcom_cfg_t *vcl_cfg = &vcm->cfg; + int fd; + unformat_input_t _input, *input = &_input; + unformat_input_t _line_input, *line_input = &_line_input; + u8 vc_cfg_input = 0; + u8 *chroot_path; + struct stat s; + u32 uid, gid; + + fd = open (conf_fname, O_RDONLY); + if (fd < 0) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] open configuration file '%s' failed!", + vcm->my_pid, conf_fname); + goto file_done; + } + + if (fstat (fd, &s) < 0) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] failed to stat `%s'", vcm->my_pid, conf_fname); + goto file_done; + } + + if (!(S_ISREG (s.st_mode) || S_ISLNK (s.st_mode))) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] not a regular file `%s'", vcm->my_pid, + conf_fname); + goto file_done; + } + + unformat_init_unix_file (input, fd); + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + unformat_user (input, unformat_line_input, line_input); + unformat_skip_white_space (line_input); + + if (unformat (line_input, "vppcom {")) + { + vc_cfg_input = 1; + continue; + } + + if (vc_cfg_input) + { + if (unformat (line_input, "heapsize %s", &chroot_path)) + { + vec_terminate_c_string (chroot_path); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured heapsize %s, " + "actual heapsize %lld (0x%llx)", + vcm->my_pid, chroot_path, vcl_cfg->heapsize, + vcl_cfg->heapsize); + vec_free (chroot_path); + } + else if (unformat (line_input, "api-prefix %s", &chroot_path)) + { + vec_terminate_c_string (chroot_path); + vl_set_memory_root_path ((char *) chroot_path); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured api-prefix %s", + vcm->my_pid, chroot_path); + chroot_path = 0; /* Don't vec_free() it! */ + } + else if (unformat (line_input, "uid %d", &uid)) + { + vl_set_memory_uid (uid); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured uid %d", vcm->my_pid, uid); + } + else if (unformat (line_input, "gid %d", &gid)) + { + vl_set_memory_gid (gid); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured gid %d", vcm->my_pid, gid); + } + else if (unformat (line_input, "segment-baseva 0x%llx", + &vcl_cfg->segment_baseva)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured segment_baseva 0x%llx", + vcm->my_pid, vcl_cfg->segment_baseva); + } + else if (unformat (line_input, "segment-size 0x%lx", + &vcl_cfg->segment_size)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured segment_size 0x%lx (%ld)", + vcm->my_pid, vcl_cfg->segment_size, + vcl_cfg->segment_size); + } + else if (unformat (line_input, "segment-size %ld", + &vcl_cfg->segment_size)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured segment_size %ld (0x%lx)", + vcm->my_pid, vcl_cfg->segment_size, + vcl_cfg->segment_size); + } + else if (unformat (line_input, "add-segment-size 0x%lx", + &vcl_cfg->add_segment_size)) + { + if (VPPCOM_DEBUG > 0) + clib_warning + ("[%d] configured add_segment_size 0x%lx (%ld)", + vcm->my_pid, vcl_cfg->add_segment_size, + vcl_cfg->add_segment_size); + } + else if (unformat (line_input, "add-segment-size %ld", + &vcl_cfg->add_segment_size)) + { + if (VPPCOM_DEBUG > 0) + clib_warning + ("[%d] configured add_segment_size %ld (0x%lx)", + vcm->my_pid, vcl_cfg->add_segment_size, + vcl_cfg->add_segment_size); + } + else if (unformat (line_input, "preallocated-fifo-pairs %d", + &vcl_cfg->preallocated_fifo_pairs)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured preallocated_fifo_pairs " + "%d (0x%x)", vcm->my_pid, + vcl_cfg->preallocated_fifo_pairs, + vcl_cfg->preallocated_fifo_pairs); + } + else if (unformat (line_input, "rx-fifo-size 0x%lx", + &vcl_cfg->rx_fifo_size)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured rx_fifo_size 0x%lx (%ld)", + vcm->my_pid, vcl_cfg->rx_fifo_size, + vcl_cfg->rx_fifo_size); + } + else if (unformat (line_input, "rx-fifo-size %ld", + &vcl_cfg->rx_fifo_size)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured rx_fifo_size %ld (0x%lx)", + vcm->my_pid, vcl_cfg->rx_fifo_size, + vcl_cfg->rx_fifo_size); + } + else if (unformat (line_input, "tx-fifo-size 0x%lx", + &vcl_cfg->tx_fifo_size)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured tx_fifo_size 0x%lx (%ld)", + vcm->my_pid, vcl_cfg->tx_fifo_size, + vcl_cfg->tx_fifo_size); + } + else if (unformat (line_input, "tx-fifo-size %ld", + &vcl_cfg->tx_fifo_size)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured tx_fifo_size %ld (0x%lx)", + vcm->my_pid, vcl_cfg->tx_fifo_size, + vcl_cfg->tx_fifo_size); + } + else if (unformat (line_input, "event-queue-size 0x%lx", + &vcl_cfg->event_queue_size)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured event_queue_size 0x%lx (%ld)", + vcm->my_pid, vcl_cfg->event_queue_size, + vcl_cfg->event_queue_size); + } + else if (unformat (line_input, "event-queue-size %ld", + &vcl_cfg->event_queue_size)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured event_queue_size %ld (0x%lx)", + vcm->my_pid, vcl_cfg->event_queue_size, + vcl_cfg->event_queue_size); + } + else if (unformat (line_input, "listen-queue-size 0x%lx", + &vcl_cfg->listen_queue_size)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured listen_queue_size 0x%lx (%ld)", + vcm->my_pid, vcl_cfg->listen_queue_size, + vcl_cfg->listen_queue_size); + } + else if (unformat (line_input, "listen-queue-size %ld", + &vcl_cfg->listen_queue_size)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured listen_queue_size %ld (0x%lx)", + vcm->my_pid, vcl_cfg->listen_queue_size, + vcl_cfg->listen_queue_size); + } + else if (unformat (line_input, "app-timeout %f", + &vcl_cfg->app_timeout)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured app_timeout %f", + vcm->my_pid, vcl_cfg->app_timeout); + } + else if (unformat (line_input, "session-timeout %f", + &vcl_cfg->session_timeout)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured session_timeout %f", + vcm->my_pid, vcl_cfg->session_timeout); + } + else if (unformat (line_input, "accept-timeout %f", + &vcl_cfg->accept_timeout)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] configured accept_timeout %f", + vcm->my_pid, vcl_cfg->accept_timeout); + } + else if (unformat (line_input, "}")) + { + vc_cfg_input = 0; + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] completed parsing vppcom config!", + vcm->my_pid); + goto input_done; + } + else + { + if (line_input->buffer[line_input->index] != '#') + { + clib_warning ("[%d] Unknown vppcom config option: '%s'", + vcm->my_pid, (char *) + &line_input->buffer[line_input->index]); + } + } + } + } + +input_done: + unformat_free (input); + +file_done: + if (fd > 0) + close (fd); +} + +/* + * VPPCOM Public API functions + */ +int +vppcom_app_create (char *app_name) +{ + vppcom_main_t *vcm = &vppcom_main; + vppcom_cfg_t *vcl_cfg = &vcm->cfg; + u8 *heap; + mheap_t *h; + int rv; + + if (!vcm->init) + { + char *conf_fname; + + vcm->init = 1; + vcm->my_pid = getpid (); + clib_fifo_validate (vcm->client_session_index_fifo, + vcm->cfg.listen_queue_size); + vppcom_cfg_init (vcl_cfg); + conf_fname = getenv (VPPCOM_CONF_ENV); + if (!conf_fname) + { + conf_fname = VPPCOM_CONF_DEFAULT; + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] getenv '%s' failed!", vcm->my_pid, + VPPCOM_CONF_ENV); + } + vppcom_cfg_heapsize (conf_fname); + vppcom_cfg_read (conf_fname); + vcm->bind_session_index = ~0; + vcm->main_cpu = os_get_thread_index (); + heap = clib_mem_get_per_cpu_heap (); + h = mheap_header (heap); + + /* make the main heap thread-safe */ + h->flags |= MHEAP_FLAG_THREAD_SAFE; + + vcm->session_index_by_vpp_handles = hash_create (0, sizeof (uword)); + + clib_time_init (&vcm->clib_time); + vppcom_init_error_string_table (); + svm_fifo_segment_init (vcl_cfg->segment_baseva, + 20 /* timeout in secs */ ); + clib_spinlock_init (&vcm->sessions_lockp); + vppcom_api_hookup (); + } + + if (vcm->my_client_index == ~0) + { + vcm->app_state = STATE_APP_START; + rv = vppcom_connect_to_vpp (app_name); + if (rv) + { + clib_warning ("[%s] couldn't connect to VPP.", vcm->my_pid); + return rv; + } + + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] sending session enable", vcm->my_pid); + + rv = vppcom_app_session_enable (); + if (rv) + { + clib_warning ("[%d] vppcom_app_session_enable() failed!", + vcm->my_pid); + return rv; + } + + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] sending app attach", vcm->my_pid); + + rv = vppcom_app_attach (); + if (rv) + { + clib_warning ("[%d] vppcom_app_attach() failed!", vcm->my_pid); + return rv; + } + } + + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] app_name '%s', my_client_index %d (0x%x)", + vcm->my_pid, app_name, vcm->my_client_index, + vcm->my_client_index); + + return VPPCOM_OK; +} + +void +vppcom_app_destroy (void) +{ + vppcom_main_t *vcm = &vppcom_main; + int rv; + + if (vcm->my_client_index == ~0) + return; + + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] detaching from VPP, my_client_index %d (0x%x)", + vcm->my_pid, vcm->my_client_index, vcm->my_client_index); + + vppcom_app_detach (); + rv = vppcom_wait_for_app_state_change (STATE_APP_ENABLED); + if (PREDICT_FALSE (rv)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] application detach timed out, rv = %s (%d)", + vcm->my_pid, vppcom_retval_str (rv), rv); + } + vl_client_disconnect_from_vlib (); + vcm->my_client_index = ~0; + vcm->app_state = STATE_APP_START; +} + +int +vppcom_session_create (u32 vrf, u8 proto, u8 is_nonblocking) +{ + vppcom_main_t *vcm = &vppcom_main; + session_t *session; + u32 session_index; + + clib_spinlock_lock (&vcm->sessions_lockp); + pool_get (vcm->sessions, session); + session_index = session - vcm->sessions; + + session->vrf = vrf; + session->proto = proto; + session->state = STATE_START; + session->is_nonblocking = is_nonblocking; + clib_spinlock_unlock (&vcm->sessions_lockp); + + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] sid %d", vcm->my_pid, session_index); + + return (int) session_index; +} + +int +vppcom_session_close (uint32_t session_index) +{ + vppcom_main_t *vcm = &vppcom_main; + session_t *session = 0; + int rv; + + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (session_index, &session); + if (PREDICT_FALSE (rv)) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, session_index); + return rv; + } + clib_spinlock_unlock (&vcm->sessions_lockp); + + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] sid %d", vcm->my_pid, session_index); + + if (session->is_cut_thru) + { + if (session->is_server) + rv = vppcom_session_unbind_cut_thru (session); + } + else + { + rv = (session->is_server) ? + vppcom_session_unbind (session_index) : + vppcom_session_disconnect (session_index); + } + + clib_spinlock_lock (&vcm->sessions_lockp); + pool_put_index (vcm->sessions, session_index); + clib_spinlock_unlock (&vcm->sessions_lockp); + return rv; +} + +int +vppcom_session_bind (uint32_t session_index, vppcom_endpt_t * ep) +{ + vppcom_main_t *vcm = &vppcom_main; + session_t *session = 0; + int rv; + + if (!ep || !ep->ip) + return VPPCOM_EINVAL; + + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (session_index, &session); + if (PREDICT_FALSE (rv)) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, session_index); + return rv; + } + + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] sid %d", vcm->my_pid, session_index); + + session->vrf = ep->vrf; + session->is_ip4 = ep->is_ip4; + memset (session->ip, 0, sizeof (*session->ip)); + clib_memcpy (session->ip, ep->ip, (ep->is_ip4 ? + sizeof (ip4_address_t) : + sizeof (ip6_address_t))); + session->port = ep->port; + + clib_spinlock_unlock (&vcm->sessions_lockp); + return VPPCOM_OK; +} + +int +vppcom_session_listen (uint32_t session_index, uint32_t q_len) +{ + vppcom_main_t *vcm = &vppcom_main; + session_t *session = 0; + int rv; + + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (session_index, &session); + if (PREDICT_FALSE (rv)) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, session_index); + return rv; + } + + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] sid %d", vcm->my_pid, session_index); + + ASSERT (vcm->bind_session_index == ~0); + vcm->bind_session_index = session_index; + vppcom_send_bind_sock (session); + clib_spinlock_unlock (&vcm->sessions_lockp); + rv = vppcom_wait_for_session_state_change (session_index, STATE_LISTEN, + vcm->cfg.session_timeout); + if (PREDICT_FALSE (rv)) + { + vcm->bind_session_index = ~0; + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] server listen timed out, rv = %d (%d)", + vcm->my_pid, vppcom_retval_str (rv), rv); + return rv; + } + + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (session_index, &session); + if (PREDICT_FALSE (rv)) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, session_index); + return rv; + } + session->is_listen = 1; + clib_spinlock_unlock (&vcm->sessions_lockp); + clib_fifo_validate (vcm->client_session_index_fifo, q_len); + + return VPPCOM_OK; +} + +int +vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep, + double wait_for_time) +{ + vppcom_main_t *vcm = &vppcom_main; + session_t *session = 0; + u32 client_session_index; + int rv; + f64 wait_for; + + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (listen_session_index, &session); + if (PREDICT_FALSE (rv)) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, listen_session_index); + return rv; + } + + if (session->state != STATE_LISTEN) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] session not in listen state, state = %s", + vcm->my_pid, vppcom_session_state_str (session->state)); + return VPPCOM_EBADFD; + } + wait_for = session->is_nonblocking ? 0 : + (wait_for_time < 0) ? vcm->cfg.accept_timeout : wait_for_time; + + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] sid %d, state %s (%d)", vcm->my_pid, + listen_session_index, + vppcom_session_state_str (session->state), session->state); + clib_spinlock_unlock (&vcm->sessions_lockp); + + while (1) + { + rv = vppcom_wait_for_client_session_index (wait_for); + if (rv) + { + if ((VPPCOM_DEBUG > 0)) + clib_warning ("[%d] sid %d, accept timed out, rv = %s (%d)", + vcm->my_pid, listen_session_index, + vppcom_retval_str (rv), rv); + if ((wait_for == 0) || (wait_for_time > 0)) + return rv; + } + else + break; + } + + clib_fifo_sub1 (vcm->client_session_index_fifo, client_session_index); + + session = 0; + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (client_session_index, &session); + ASSERT (rv == VPPCOM_OK); + ASSERT (session->is_server); + + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] Got a request: client sid %d", vcm->my_pid, + client_session_index); + + ep->vrf = session->vrf; + ep->is_cut_thru = session->is_cut_thru; + ep->is_ip4 = session->is_ip4; + ep->port = session->port; + memset (ep->ip, 0, sizeof (ip6_address_t)); + clib_memcpy (ep->ip, session->ip, (session->is_ip4 ? + sizeof (ip4_address_t) : + sizeof (ip6_address_t))); + session->state = STATE_LISTEN; + clib_spinlock_unlock (&vcm->sessions_lockp); + return (int) client_session_index; +} + +int +vppcom_session_connect (uint32_t session_index, vppcom_endpt_t * server_ep) +{ + vppcom_main_t *vcm = &vppcom_main; + session_t *session = 0; + int rv; + ip46_address_t *ip46; + + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (session_index, &session); + if (PREDICT_FALSE (rv)) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, session_index); + return rv; + } + + if (session->state == STATE_CONNECT) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] session, sid (%d) already connected!", + vcm->my_pid, session_index); + return VPPCOM_OK; + } + + session->vrf = server_ep->vrf; + session->is_ip4 = server_ep->is_ip4; + ip46 = (ip46_address_t *) session->ip; + *ip46 = to_ip46 (!server_ep->is_ip4, server_ep->ip); + session->port = server_ep->port; + + if (VPPCOM_DEBUG > 0) + { + u8 *ip_str = format (0, "%U", format_ip46_address, + &session->ip, session->is_ip4); + clib_warning ("[%d] connect sid %d to %s server port %d", + vcm->my_pid, session_index, ip_str, + clib_net_to_host_u16 (session->port)); + vec_free (ip_str); + } + + vppcom_send_connect_sock (session, session_index); + clib_spinlock_unlock (&vcm->sessions_lockp); + rv = vppcom_wait_for_session_state_change (session_index, STATE_CONNECT, + vcm->cfg.session_timeout); + if (PREDICT_FALSE (rv)) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] connect timed out, rv = %s (%d)", + vcm->my_pid, vppcom_retval_str (rv), rv); + return rv; + } + return VPPCOM_OK; +} + +int +vppcom_session_read (uint32_t session_index, void *buf, int n) +{ + session_fifo_event_t _e, *e = &_e; + vppcom_main_t *vcm = &vppcom_main; + session_t *session = 0; + svm_fifo_t *rx_fifo; + int n_read = 0; + int rv; + char *fifo_str; + + ASSERT (buf); + + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (session_index, &session); + if (PREDICT_FALSE (rv)) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, session_index); + return rv; + } + + if (session->is_cut_thru) + { + rx_fifo = session->is_server ? session->server_rx_fifo : + session->server_tx_fifo; + fifo_str = session->is_server ? "server_rx_fifo" : "server_tx_fifo"; + clib_spinlock_unlock (&vcm->sessions_lockp); + + n_read = svm_fifo_dequeue_nowait (rx_fifo, n, buf); + + if (n_read <= 0) + return VPPCOM_EAGAIN; + + } + else + { + rv = unix_shared_memory_queue_sub (session->event_queue, (u8 *) e, + 1 /* nowait */ ); + clib_spinlock_unlock (&vcm->sessions_lockp); + if (rv < 0) + return VPPCOM_EAGAIN; + + switch (e->event_type) + { + case FIFO_EVENT_APP_RX: + rx_fifo = e->fifo; + fifo_str = "app_rx_fifo"; + n_read = svm_fifo_dequeue_nowait (rx_fifo, n, buf); + break; + + case FIFO_EVENT_DISCONNECT: + return VPPCOM_ECONNRESET; + + default: + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] unknown event type %d", vcm->my_pid, + e->event_type); + return VPPCOM_EAGAIN; + } + } + + if (VPPCOM_DEBUG > 2) + clib_warning ("[%d] sid %d, read %d bytes from %s (%p)", vcm->my_pid, + session_index, n_read, fifo_str, rx_fifo); + return n_read; +} + +static inline int +vppcom_session_read_ready (session_t * session, u32 session_index) +{ + session_fifo_event_t _e, *e = &_e; + vppcom_main_t *vcm = &vppcom_main; + svm_fifo_t *rx_fifo; + int rv; + int ready = 0; + + /* Assumes caller has acquired spinlock: vcm->sessions_lockp */ + if (session->is_cut_thru) + { + rx_fifo = session->is_server ? session->server_rx_fifo : + session->server_tx_fifo; + + ready = svm_fifo_max_dequeue (rx_fifo); + } + else if (session->is_listen) + ready = clib_fifo_elts (vcm->client_session_index_fifo); + else + { + rv = unix_shared_memory_queue_sub (vcm->app_event_queue, (u8 *) e, + 1 /* nowait */ ); + if (rv >= 0) + { + switch (e->event_type) + { + case FIFO_EVENT_APP_RX: + rx_fifo = e->fifo; + ready = svm_fifo_max_dequeue (rx_fifo); + break; + + case FIFO_EVENT_DISCONNECT: + return VPPCOM_ECONNRESET; + + default: + clib_warning ("[%d] unknown event type %d", vcm->my_pid, + e->event_type); + } + } + } + + if (VPPCOM_DEBUG > 2) + clib_warning ("[%d] sid %d, peek %s (%p), ready = %d", vcm->my_pid, + session_index, + session->is_server ? "server_rx_fifo" : "server_tx_fifo", + rx_fifo, ready); + + return ready; +} + +int +vppcom_session_write (uint32_t session_index, void *buf, int n) +{ + vppcom_main_t *vcm = &vppcom_main; + session_t *session = 0; + svm_fifo_t *tx_fifo; + unix_shared_memory_queue_t *q; + session_fifo_event_t evt; + int rv; + char *fifo_str; + u8 is_nonblocking; + + ASSERT (buf); + + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (session_index, &session); + if (PREDICT_FALSE (rv)) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, session_index); + return rv; + } + + tx_fifo = ((!session->is_cut_thru || session->is_server) ? + session->server_tx_fifo : session->server_rx_fifo); + fifo_str = ((!session->is_cut_thru || session->is_server) ? + "server_tx_fifo" : "server_rx_fifo"); + is_nonblocking = session->is_nonblocking; + clib_spinlock_unlock (&vcm->sessions_lockp); + + do + { + rv = svm_fifo_enqueue_nowait (tx_fifo, n, buf); + } + while (!is_nonblocking && (rv <= 0)); + + /* If event wasn't set, add one */ + if ((rv > 0) && svm_fifo_set_event (tx_fifo)) + { + int rval; + + /* Fabricate TX event, send to vpp */ + evt.fifo = tx_fifo; + evt.event_type = FIFO_EVENT_APP_TX; + evt.event_id = vcm->tx_event_id++; + + clib_spinlock_lock (&vcm->sessions_lockp); + rval = vppcom_session_at_index (session_index, &session); + if (PREDICT_FALSE (rval)) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] invalid session, sid (%d) has been closed!", + vcm->my_pid, session_index); + return rval; + } + q = session->event_queue; + clib_spinlock_unlock (&vcm->sessions_lockp); + ASSERT (q); + unix_shared_memory_queue_add (q, (u8 *) & evt, + 0 /* do wait for mutex */ ); + } + + if (VPPCOM_DEBUG > 2) + clib_warning ("[%d] sid %d, wrote %d bytes to %s (%p)", vcm->my_pid, + session_index, rv, fifo_str, tx_fifo); + + return rv; +} + +static inline int +vppcom_session_write_ready (session_t * session, u32 session_index) +{ + vppcom_main_t *vcm = &vppcom_main; + svm_fifo_t *tx_fifo; + int rv; + + /* Assumes caller has acquired spinlock: vcm->sessions_lockp */ + tx_fifo = ((!session->is_cut_thru || session->is_server) ? + session->server_tx_fifo : session->server_rx_fifo); + + rv = svm_fifo_max_enqueue (tx_fifo); + + if (VPPCOM_DEBUG > 2) + clib_warning ("[%d] sid %d, peek %s (%p), ready = %d", vcm->my_pid, + session_index, + session->is_server ? "server_tx_fifo" : "server_rx_fifo", + tx_fifo, rv); + return rv; +} + +int +vppcom_select (unsigned long n_bits, unsigned long *read_map, + unsigned long *write_map, unsigned long *except_map, + double time_to_wait) +{ + vppcom_main_t *vcm = &vppcom_main; + u32 session_index; + session_t *session = 0; + int rv, bits_set = 0; + f64 timeout = clib_time_now (&vcm->clib_time) + time_to_wait; + u32 minbits = clib_max (n_bits, BITS (uword)); + + ASSERT (sizeof (clib_bitmap_t) == sizeof (long int)); + + if (read_map) + { + clib_bitmap_validate (vcm->rd_bitmap, minbits); + clib_memcpy (vcm->rd_bitmap, read_map, vec_len (vcm->rd_bitmap)); + memset (read_map, 0, vec_len (vcm->rd_bitmap)); + } + if (write_map) + { + clib_bitmap_validate (vcm->wr_bitmap, minbits); + clib_memcpy (vcm->wr_bitmap, write_map, vec_len (vcm->wr_bitmap)); + memset (write_map, 0, vec_len (vcm->wr_bitmap)); + } + if (except_map) + { + clib_bitmap_validate (vcm->ex_bitmap, minbits); + clib_memcpy (vcm->ex_bitmap, except_map, vec_len (vcm->ex_bitmap)); + memset (except_map, 0, vec_len (vcm->ex_bitmap)); + } + + do + { + /* *INDENT-OFF* */ + clib_bitmap_foreach (session_index, vcm->rd_bitmap, + ({ + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (session_index, &session); + if (rv < 0) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] session %d specified in " + "read_map is closed.", vcm->my_pid, + session_index); + bits_set = VPPCOM_EBADFD; + goto select_done; + } + + rv = vppcom_session_read_ready (session, session_index); + clib_spinlock_unlock (&vcm->sessions_lockp); + if (vcm->ex_bitmap && + clib_bitmap_get (vcm->ex_bitmap, session_index) && (rv < 0)) + { + // TBD: clib_warning + clib_bitmap_set_no_check (except_map, session_index, 1); + bits_set++; + } + else if (rv > 0) + { + // TBD: clib_warning + clib_bitmap_set_no_check (read_map, session_index, 1); + bits_set++; + } + })); + + clib_bitmap_foreach (session_index, vcm->wr_bitmap, + ({ + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (session_index, &session); + if (rv < 0) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] session %d specified in " + "write_map is closed.", vcm->my_pid, + session_index); + bits_set = VPPCOM_EBADFD; + goto select_done; + } + + rv = vppcom_session_write_ready (session, session_index); + clib_spinlock_unlock (&vcm->sessions_lockp); + if (rv > 0) + { + // TBD: clib_warning + clib_bitmap_set_no_check (write_map, session_index, 1); + bits_set++; + } + })); + + clib_bitmap_foreach (session_index, vcm->ex_bitmap, + ({ + clib_spinlock_lock (&vcm->sessions_lockp); + rv = vppcom_session_at_index (session_index, &session); + if (rv < 0) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 1) + clib_warning ("[%d] session %d specified in " + "except_map is closed.", vcm->my_pid, + session_index); + bits_set = VPPCOM_EBADFD; + goto select_done; + } + + rv = vppcom_session_read_ready (session, session_index); + clib_spinlock_unlock (&vcm->sessions_lockp); + if (rv < 0) + { + // TBD: clib_warning + clib_bitmap_set_no_check (except_map, session_index, 1); + bits_set++; + } + })); + /* *INDENT-ON* */ + } + while (clib_time_now (&vcm->clib_time) < timeout); + +select_done: + return (bits_set); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg From 6d5c4cdbcc4799a9f43df68df434d5786db44b45 Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Tue, 15 Aug 2017 16:56:29 -0400 Subject: VCL: copy complete ip addr to/from vpe-api buf. Change-Id: I951e051278e775a7ecdaa88af812f535727baa92 Signed-off-by: Dave Wallace --- src/uri/vppcom.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) (limited to 'src/uri/vppcom.c') diff --git a/src/uri/vppcom.c b/src/uri/vppcom.c index 44208cc0..9a4bea8f 100644 --- a/src/uri/vppcom.c +++ b/src/uri/vppcom.c @@ -783,9 +783,7 @@ vppcom_send_connect_sock (session_t * session, u32 session_index) cmp->vrf = session->vrf; cmp->is_ip4 = session->is_ip4; - clib_memcpy (cmp->ip, session->ip, (session->is_ip4 ? - sizeof (ip4_address_t) : - sizeof (ip6_address_t))); + clib_memcpy (cmp->ip, session->ip, sizeof (cmp->ip)); cmp->port = session->port; cmp->proto = session->proto; clib_memcpy (cmp->options, session->options, sizeof (cmp->options)); @@ -999,9 +997,7 @@ vl_api_accept_session_t_handler (vl_api_accept_session_t * mp) session->is_cut_thru = 0; session->port = ntohs (mp->port); session->is_ip4 = mp->is_ip4; - clib_memcpy (session->ip, mp->ip, (mp->is_ip4 ? - sizeof (ip4_address_t) : - sizeof (ip6_address_t))); + clib_memcpy (session->ip, mp->ip, sizeof (session->ip)); clib_spinlock_unlock (&vcm->sessions_lockp); /* Add it to lookup table */ @@ -1130,9 +1126,8 @@ vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp) ssvm_pop_heap (oldheap); ssvm_unlock_non_recursive (sh); } - clib_memcpy (session->ip, mp->ip, (mp->is_ip4 ? - sizeof (ip4_address_t) : - sizeof (ip6_address_t))); + clib_memcpy (session->ip, mp->ip, sizeof (session->ip)); + session->state = STATE_ACCEPT; if (VPPCOM_DEBUG > 1) clib_warning ("[%d] Connected cut-thru to client: sid %d", @@ -1181,9 +1176,7 @@ vppcom_send_bind_sock (session_t * session) bmp->context = htonl (0xfeedface); bmp->vrf = session->vrf; bmp->is_ip4 = session->is_ip4; - clib_memcpy (bmp->ip, session->ip, (session->is_ip4 ? - sizeof (ip4_address_t) : - sizeof (ip6_address_t))); + clib_memcpy (bmp->ip, session->ip, sizeof (bmp->ip)); bmp->port = session->port; bmp->proto = session->proto; clib_memcpy (bmp->options, session->options, sizeof (bmp->options)); @@ -1906,9 +1899,7 @@ vppcom_session_bind (uint32_t session_index, vppcom_endpt_t * ep) session->vrf = ep->vrf; session->is_ip4 = ep->is_ip4; memset (session->ip, 0, sizeof (*session->ip)); - clib_memcpy (session->ip, ep->ip, (ep->is_ip4 ? - sizeof (ip4_address_t) : - sizeof (ip6_address_t))); + clib_memcpy (session->ip, ep->ip, sizeof (session->ip)); session->port = ep->port; clib_spinlock_unlock (&vcm->sessions_lockp); @@ -2039,9 +2030,7 @@ vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep, ep->is_ip4 = session->is_ip4; ep->port = session->port; memset (ep->ip, 0, sizeof (ip6_address_t)); - clib_memcpy (ep->ip, session->ip, (session->is_ip4 ? - sizeof (ip4_address_t) : - sizeof (ip6_address_t))); + clib_memcpy (ep->ip, session->ip, sizeof (ip6_address_t)); session->state = STATE_LISTEN; clib_spinlock_unlock (&vcm->sessions_lockp); return (int) client_session_index; -- cgit 1.2.3-korg From c87c91d8b0e85997debaf575f2e30cc2702edf25 Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Wed, 16 Aug 2017 19:55:49 -0700 Subject: session: segment manager improvements - cleanup connects segment manager even if first - fix segment manager allocation for listen sessions - improve handling of process private segments (mheaps/main heap) - added segment manager cli Change-Id: Ic2ca97c3622ab2286d5fb5772aeb57680e64f769 Signed-off-by: Florin Coras Signed-off-by: Dave Wallace --- src/svm/svm_fifo_segment.c | 62 +++++-- src/svm/svm_fifo_segment.h | 13 +- src/svm/test_svm_fifo1.c | 10 +- src/uri/vppcom.c | 2 +- src/vnet/session/application.c | 71 ++++++-- src/vnet/session/application.h | 8 +- src/vnet/session/segment_manager.c | 365 +++++++++++++++++++++++++------------ src/vnet/session/segment_manager.h | 29 +-- src/vnet/session/session.c | 9 +- src/vnet/session/session_cli.c | 19 +- src/vnet/session/session_node.c | 3 +- src/vnet/tcp/tcp.c | 6 +- 12 files changed, 407 insertions(+), 190 deletions(-) (limited to 'src/uri/vppcom.c') diff --git a/src/svm/svm_fifo_segment.c b/src/svm/svm_fifo_segment.c index 2094ba74..6600a423 100644 --- a/src/svm/svm_fifo_segment.c +++ b/src/svm/svm_fifo_segment.c @@ -188,7 +188,7 @@ svm_fifo_segment_create (svm_fifo_segment_create_args_t * a) return (rv); } - /* Note; requested_va updated due to seg base addr randomization */ + /* Note: requested_va updated due to seg base addr randomization */ sm->next_baseva = s->ssvm.requested_va + a->segment_size; sh = s->ssvm.sh; @@ -200,7 +200,6 @@ svm_fifo_segment_create (svm_fifo_segment_create_args_t * a) sh->opaque[0] = fsh; s->h = fsh; fsh->segment_name = format (0, "%s%c", a->segment_name, 0); - preallocate_fifo_pairs (fsh, a); ssvm_pop_heap (oldheap); @@ -226,25 +225,19 @@ svm_fifo_segment_create_process_private (svm_fifo_segment_create_args_t * a) if (a->private_segment_count && a->private_segment_size) { - void *mem; u8 *heap; u32 pagesize = clib_mem_get_page_size (); u32 rnd_size; + rnd_size = (a->private_segment_size + (pagesize - 1)) & ~pagesize; for (i = 0; i < a->private_segment_count; i++) { - rnd_size = (a->private_segment_size + (pagesize - 1)) & ~pagesize; - - mem = mmap (0, rnd_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, - -1 /* fd */ , 0 /* offset */ ); - - if (mem == MAP_FAILED) + heap = mheap_alloc (0, rnd_size); + if (heap == 0) { - clib_unix_warning ("mmap"); + clib_unix_warning ("mheap alloc"); return -1; } - heap = mheap_alloc (mem, rnd_size); heap_header = mheap_header (heap); heap_header->flags |= MHEAP_FLAG_THREAD_SAFE; vec_add1 (heaps, heap); @@ -279,6 +272,9 @@ svm_fifo_segment_create_process_private (svm_fifo_segment_create_args_t * a) memset (fsh, 0, sizeof (*fsh)); sh->opaque[0] = fsh; s->h = fsh; + fsh->flags = FIFO_SEGMENT_F_IS_PRIVATE; + if (!a->private_segment_count) + fsh->flags |= FIFO_SEGMENT_F_IS_MAIN_HEAP; fsh->segment_name = format (0, "%s%c", a->segment_name, 0); if (a->private_segment_count) @@ -288,7 +284,6 @@ svm_fifo_segment_create_process_private (svm_fifo_segment_create_args_t * a) preallocate_fifo_pairs (fsh, a); clib_mem_set_heap (oldheap); } - sh->ready = 1; vec_add1 (a->new_segment_indices, s - sm->segments); } @@ -336,8 +331,20 @@ void svm_fifo_segment_delete (svm_fifo_segment_private_t * s) { svm_fifo_segment_main_t *sm = &svm_fifo_segment_main; - ssvm_delete (&s->ssvm); - pool_put (sm->segments, s); + if (s->h->flags & FIFO_SEGMENT_F_IS_PRIVATE) + { + /* Don't try to free vpp's heap! */ + if (!(s->h->flags & FIFO_SEGMENT_F_IS_MAIN_HEAP)) + mheap_free (s->ssvm.sh->heap); + clib_mem_free (s->ssvm.sh); + clib_mem_free (s->h); + pool_put (sm->segments, s); + } + else + { + ssvm_delete (&s->ssvm); + pool_put (sm->segments, s); + } } svm_fifo_t * @@ -352,8 +359,8 @@ svm_fifo_segment_alloc_fifo (svm_fifo_segment_private_t * s, int freelist_index; /* - * 2K minimum. It's not likely that anything good will happen - * with a 1K FIFO. + * 4K minimum. It's not likely that anything good will happen + * with a smaller FIFO. */ if (data_size_in_bytes < FIFO_SEGMENT_MIN_FIFO_SIZE || data_size_in_bytes > FIFO_SEGMENT_MAX_FIFO_SIZE) @@ -428,6 +435,7 @@ found: } fsh->fifos = f; } + fsh->n_active_fifos++; ssvm_pop_heap (oldheap); ssvm_unlock_non_recursive (sh); @@ -489,6 +497,7 @@ svm_fifo_segment_free_fifo (svm_fifo_segment_private_t * s, svm_fifo_t * f, f->master_thread_index = ~0; } + fsh->n_active_fifos--; ssvm_pop_heap (oldheap); ssvm_unlock_non_recursive (sh); } @@ -508,6 +517,25 @@ svm_fifo_segment_index (svm_fifo_segment_private_t * s) return s - svm_fifo_segment_main.segments; } +/** + * Retrieve svm segments pool. Used only for debug purposes. + */ +svm_fifo_segment_private_t * +svm_fifo_segment_segments_pool (void) +{ + svm_fifo_segment_main_t *sm = &svm_fifo_segment_main; + return sm->segments; +} + +/** + * Get number of active fifos + */ +u32 +svm_fifo_segment_num_fifos (svm_fifo_segment_private_t * fifo_segment) +{ + return fifo_segment->h->n_active_fifos; +} + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/svm/svm_fifo_segment.h b/src/svm/svm_fifo_segment.h index 68bb4d3d..5cc4754a 100644 --- a/src/svm/svm_fifo_segment.h +++ b/src/svm/svm_fifo_segment.h @@ -27,15 +27,20 @@ typedef enum FIFO_SEGMENT_N_FREELISTS } svm_fifo_segment_freelist_t; -#define FIFO_SEGMENT_MIN_FIFO_SIZE 2048 +#define FIFO_SEGMENT_MIN_FIFO_SIZE 4096 #define FIFO_SEGMENT_MAX_FIFO_SIZE (8<<20) /* 8mb max fifo size */ -#define FIFO_SEGMENT_ALLOC_CHUNK_SIZE 32 /* allocation quantum */ +#define FIFO_SEGMENT_ALLOC_CHUNK_SIZE 32 /* Allocation quantum */ + +#define FIFO_SEGMENT_F_IS_PRIVATE 1 << 0 /* Private segment */ +#define FIFO_SEGMENT_F_IS_MAIN_HEAP 1 << 1 /* Segment is main heap */ typedef struct { svm_fifo_t *fifos; /**< Linked list of active RX fifos */ u8 *segment_name; /**< Segment name */ svm_fifo_t **free_fifos; /**< Freelists, by fifo size */ + u32 n_active_fifos; /**< Number of active fifos */ + u8 flags; /**< Segment flags */ } svm_fifo_segment_header_t; typedef struct @@ -70,7 +75,7 @@ typedef struct } svm_fifo_segment_create_args_t; static inline svm_fifo_segment_private_t * -svm_fifo_get_segment (u32 segment_index) +svm_fifo_segment_get_segment (u32 segment_index) { svm_fifo_segment_main_t *ssm = &svm_fifo_segment_main; return vec_elt_at_index (ssm->segments, segment_index); @@ -112,6 +117,8 @@ void svm_fifo_segment_free_fifo (svm_fifo_segment_private_t * s, svm_fifo_segment_freelist_t index); void svm_fifo_segment_init (u64 baseva, u32 timeout_in_seconds); u32 svm_fifo_segment_index (svm_fifo_segment_private_t * s); +u32 svm_fifo_segment_num_fifos (svm_fifo_segment_private_t * fifo_segment); +svm_fifo_segment_private_t *svm_fifo_segment_segments_pool (void); #endif /* __included_ssvm_fifo_segment_h__ */ diff --git a/src/svm/test_svm_fifo1.c b/src/svm/test_svm_fifo1.c index 63d75845..3bdca949 100644 --- a/src/svm/test_svm_fifo1.c +++ b/src/svm/test_svm_fifo1.c @@ -39,7 +39,7 @@ hello_world (int verbose) if (rv) return clib_error_return (0, "svm_fifo_segment_create returned %d", rv); - sp = svm_fifo_get_segment (a->new_segment_indices[0]); + sp = svm_fifo_segment_get_segment (a->new_segment_indices[0]); f = svm_fifo_segment_alloc_fifo (sp, 4096, FIFO_SEGMENT_RX_FREELIST); @@ -92,7 +92,7 @@ master (int verbose) if (rv) return clib_error_return (0, "svm_fifo_segment_create returned %d", rv); - sp = svm_fifo_get_segment (a->new_segment_indices[0]); + sp = svm_fifo_segment_get_segment (a->new_segment_indices[0]); f = svm_fifo_segment_alloc_fifo (sp, 4096, FIFO_SEGMENT_RX_FREELIST); @@ -128,7 +128,7 @@ mempig (int verbose) if (rv) return clib_error_return (0, "svm_fifo_segment_create returned %d", rv); - sp = svm_fifo_get_segment (a->new_segment_indices[0]); + sp = svm_fifo_segment_get_segment (a->new_segment_indices[0]); for (i = 0; i < 1000; i++) { @@ -186,7 +186,7 @@ offset (int verbose) if (rv) return clib_error_return (0, "svm_fifo_segment_create returned %d", rv); - sp = svm_fifo_get_segment (a->new_segment_indices[0]); + sp = svm_fifo_segment_get_segment (a->new_segment_indices[0]); f = svm_fifo_segment_alloc_fifo (sp, 200 << 10, FIFO_SEGMENT_RX_FREELIST); @@ -246,7 +246,7 @@ slave (int verbose) if (rv) return clib_error_return (0, "svm_fifo_segment_attach returned %d", rv); - sp = svm_fifo_get_segment (a->new_segment_indices[0]); + sp = svm_fifo_segment_get_segment (a->new_segment_indices[0]); sh = sp->ssvm.sh; fsh = (svm_fifo_segment_header_t *) sh->opaque[0]; diff --git a/src/uri/vppcom.c b/src/uri/vppcom.c index 9a4bea8f..c41acd54 100644 --- a/src/uri/vppcom.c +++ b/src/uri/vppcom.c @@ -1076,7 +1076,7 @@ vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp) session->sm_seg_index = a->new_segment_indices[0]; vec_reset_length (a->new_segment_indices); - seg = svm_fifo_get_segment (session->sm_seg_index); + seg = svm_fifo_segment_get_segment (session->sm_seg_index); rx_fifo = session->server_rx_fifo = svm_fifo_segment_alloc_fifo (seg, vcm->cfg.rx_fifo_size, FIFO_SEGMENT_RX_FREELIST); diff --git a/src/vnet/session/application.c b/src/vnet/session/application.c index 25a4efa5..d105119c 100644 --- a/src/vnet/session/application.c +++ b/src/vnet/session/application.c @@ -80,8 +80,8 @@ application_new () pool_get (app_pool, app); memset (app, 0, sizeof (*app)); app->index = application_get_index (app); - app->connects_seg_manager = ~0; - app->first_segment_manager = ~0; + app->connects_seg_manager = APP_INVALID_SEGMENT_MANAGER_INDEX; + app->first_segment_manager = APP_INVALID_SEGMENT_MANAGER_INDEX; if (CLIB_DEBUG > 1) clib_warning ("[%d] New app (%d)", getpid (), app->index); return app; @@ -104,14 +104,8 @@ application_del (application_t * app) clib_warning ("[%d] Delete app (%d)", getpid (), app->index); /* - * Cleanup segment managers + * Listener cleanup */ - if ((app->connects_seg_manager != (u32) ~ 0) && - (app->connects_seg_manager != app->first_segment_manager)) - { - sm = segment_manager_get (app->connects_seg_manager); - segment_manager_del (sm); - } /* *INDENT-OFF* */ hash_foreach (handle, index, app->listeners_table, @@ -120,7 +114,6 @@ application_del (application_t * app) })); /* *INDENT-ON* */ - /* Actual listener cleanup */ for (i = 0; i < vec_len (handles); i++) { a->app_index = app->index; @@ -129,10 +122,30 @@ application_del (application_t * app) vnet_unbind (a); } - if (app->first_segment_manager != ~0) + /* + * Connects segment manager cleanup + */ + + if (app->connects_seg_manager != APP_INVALID_SEGMENT_MANAGER_INDEX) + { + sm = segment_manager_get (app->connects_seg_manager); + sm->app_index = SEGMENT_MANAGER_INVALID_APP_INDEX; + segment_manager_init_del (sm); + } + + + /* If first segment manager is used by a listener */ + if (app->first_segment_manager != APP_INVALID_SEGMENT_MANAGER_INDEX + && app->first_segment_manager != app->connects_seg_manager) { sm = segment_manager_get (app->first_segment_manager); - segment_manager_first_segment_maybe_del (sm); + /* .. and has no fifos, e.g. it might be used for redirected sessions, + * remove it */ + if (!segment_manager_has_fifos (sm)) + { + sm->app_index = SEGMENT_MANAGER_INVALID_APP_INDEX; + segment_manager_del (sm); + } } application_table_del (app); @@ -159,6 +172,7 @@ application_init (application_t * app, u32 api_client_index, u64 * options, segment_manager_t *sm; segment_manager_properties_t *props; u32 app_evt_queue_size, first_seg_size; + u32 default_rx_fifo_size = 16 << 10, default_tx_fifo_size = 16 << 10; int rv; app_evt_queue_size = options[APP_EVT_QUEUE_SIZE] > 0 ? @@ -170,7 +184,11 @@ application_init (application_t * app, u32 api_client_index, u64 * options, props = &app->sm_properties; props->add_segment_size = options[SESSION_OPTIONS_ADD_SEGMENT_SIZE]; props->rx_fifo_size = options[SESSION_OPTIONS_RX_FIFO_SIZE]; + props->rx_fifo_size = + props->rx_fifo_size ? props->rx_fifo_size : default_rx_fifo_size; props->tx_fifo_size = options[SESSION_OPTIONS_TX_FIFO_SIZE]; + props->tx_fifo_size = + props->tx_fifo_size ? props->tx_fifo_size : default_tx_fifo_size; props->add_segment = props->add_segment_size != 0; props->preallocated_fifo_pairs = options[APP_OPTIONS_PREALLOC_FIFO_PAIRS]; props->use_private_segment = options[APP_OPTIONS_FLAGS] @@ -181,6 +199,7 @@ application_init (application_t * app, u32 api_client_index, u64 * options, first_seg_size = options[SESSION_OPTIONS_SEGMENT_SIZE]; if ((rv = segment_manager_init (sm, props, first_seg_size))) return rv; + sm->first_is_protected = 1; app->first_segment_manager = segment_manager_index (sm); app->api_client_index = api_client_index; @@ -225,7 +244,8 @@ application_alloc_segment_manager (application_t * app) { segment_manager_t *sm = 0; - if (app->first_segment_manager != (u32) ~ 0 + /* If the first segment manager is not in use, don't allocate a new one */ + if (app->first_segment_manager != APP_INVALID_SEGMENT_MANAGER_INDEX && app->first_segment_manager_in_use == 0) { sm = segment_manager_get (app->first_segment_manager); @@ -302,11 +322,15 @@ application_stop_listen (application_t * srv, u64 handle) ASSERT (indexp); sm = segment_manager_get (*indexp); - segment_manager_del (sm); if (srv->first_segment_manager == *indexp) { + /* Delete sessions but don't remove segment manager */ srv->first_segment_manager_in_use = 0; - srv->first_segment_manager = ~0; + segment_manager_del_sessions (sm); + } + else + { + segment_manager_init_del (sm); } hash_unset (srv->listeners_table, handle); listen_session_del (listener); @@ -379,6 +403,21 @@ application_is_proxy (application_t * app) return !(app->flags & APP_OPTIONS_FLAGS_IS_PROXY); } +int +application_add_segment_notify (u32 app_index, u32 fifo_segment_index) +{ + application_t *app = application_get (app_index); + u32 seg_size = 0; + u8 *seg_name; + + /* Send an API message to the external app, to map new segment */ + ASSERT (app->cb_fns.add_segment_callback); + + segment_manager_get_segment_info (fifo_segment_index, &seg_name, &seg_size); + return app->cb_fns.add_segment_callback (app->api_client_index, seg_name, + seg_size); +} + u8 * format_application_listener (u8 * s, va_list * args) { @@ -449,7 +488,7 @@ application_format_connects (application_t * app, int verbose) svm_fifo_t *fifo; u8 *str; - fifo_segment = svm_fifo_get_segment (sm->segment_indices[j]); + fifo_segment = svm_fifo_segment_get_segment (sm->segment_indices[j]); fifo = svm_fifo_segment_get_fifo_list (fifo_segment); while (fifo) { diff --git a/src/vnet/session/application.h b/src/vnet/session/application.h index 95a39c05..e030c376 100644 --- a/src/vnet/session/application.h +++ b/src/vnet/session/application.h @@ -82,9 +82,12 @@ typedef struct _application */ u32 connects_seg_manager; - /* Lookup tables for listeners. Value is segment manager index */ + /** Lookup tables for listeners. Value is segment manager index */ uword *listeners_table; + /** First segment manager has in the the first segment the application's + * event fifo. Depending on what the app does, it may be either used for + * a listener or for connects. */ u32 first_segment_manager; u8 first_segment_manager_in_use; @@ -92,6 +95,8 @@ typedef struct _application segment_manager_properties_t sm_properties; } application_t; +#define APP_INVALID_SEGMENT_MANAGER_INDEX ((u32) ~0) + application_t *application_new (); int application_init (application_t * app, u32 api_client_index, u64 * options, @@ -118,6 +123,7 @@ segment_manager_t *application_get_listen_segment_manager (application_t * segment_manager_t *application_get_connect_segment_manager (application_t * app); int application_is_proxy (application_t * app); +int application_add_segment_notify (u32 app_index, u32 fifo_segment_index); #endif /* SRC_VNET_SESSION_APPLICATION_H_ */ diff --git a/src/vnet/session/segment_manager.c b/src/vnet/session/segment_manager.c index 43977063..7cf66ee3 100644 --- a/src/vnet/session/segment_manager.c +++ b/src/vnet/session/segment_manager.c @@ -42,7 +42,7 @@ void segment_manager_get_segment_info (u32 index, u8 ** name, u32 * size) { svm_fifo_segment_private_t *s; - s = svm_fifo_get_segment (index); + s = svm_fifo_segment_get_segment (index); *name = s->h->segment_name; *size = s->ssvm.ssvm_size; } @@ -56,23 +56,39 @@ session_manager_add_segment_i (segment_manager_t * sm, u32 segment_size, memset (ca, 0, sizeof (*ca)); - ca->segment_name = (char *) segment_name; - ca->segment_size = segment_size; - ca->rx_fifo_size = sm->properties->rx_fifo_size; - ca->tx_fifo_size = sm->properties->tx_fifo_size; - ca->preallocated_fifo_pairs = sm->properties->preallocated_fifo_pairs; + if (!sm->properties->use_private_segment) + { + ca->segment_name = (char *) segment_name; + ca->segment_size = segment_size; + ca->rx_fifo_size = sm->properties->rx_fifo_size; + ca->tx_fifo_size = sm->properties->tx_fifo_size; + ca->preallocated_fifo_pairs = sm->properties->preallocated_fifo_pairs; - rv = svm_fifo_segment_create (ca); - if (rv) + rv = svm_fifo_segment_create (ca); + if (rv) + { + clib_warning ("svm_fifo_segment_create ('%s', %d) failed", + ca->segment_name, ca->segment_size); + return VNET_API_ERROR_SVM_SEGMENT_CREATE_FAIL; + } + } + else { - clib_warning ("svm_fifo_segment_create ('%s', %d) failed", - ca->segment_name, ca->segment_size); - return VNET_API_ERROR_SVM_SEGMENT_CREATE_FAIL; + ca->segment_name = "process-private-segment"; + ca->segment_size = ~0; + ca->rx_fifo_size = sm->properties->rx_fifo_size; + ca->tx_fifo_size = sm->properties->tx_fifo_size; + ca->preallocated_fifo_pairs = sm->properties->preallocated_fifo_pairs; + ca->private_segment_count = sm->properties->private_segment_count; + ca->private_segment_size = sm->properties->private_segment_size; + + if (svm_fifo_segment_create_process_private (ca)) + clib_warning ("Failed to create process private segment"); + + ASSERT (vec_len (ca->new_segment_indices)); } - vec_append (sm->segment_indices, ca->new_segment_indices); vec_free (ca->new_segment_indices); - return 0; } @@ -106,29 +122,13 @@ session_manager_add_first_segment (segment_manager_t * sm, u32 segment_size) return rv; } -static void - segment_manager_alloc_process_private_segment - (segment_manager_properties_t * props) +segment_manager_t * +segment_manager_new () { - svm_fifo_segment_create_args_t _a, *a = &_a; - - if (private_segment_indices) - return; - - memset (a, 0, sizeof (*a)); - a->segment_name = "process-private-segment"; - a->segment_size = ~0; - a->rx_fifo_size = props->rx_fifo_size; - a->tx_fifo_size = props->tx_fifo_size; - a->preallocated_fifo_pairs = props->preallocated_fifo_pairs; - a->private_segment_count = props->private_segment_count; - a->private_segment_size = props->private_segment_size; - - if (svm_fifo_segment_create_process_private (a)) - clib_warning ("Failed to create process private segment"); - - private_segment_indices = a->new_segment_indices; - ASSERT (vec_len (private_segment_indices)); + segment_manager_t *sm; + pool_get (segment_managers, sm); + memset (sm, 0, sizeof (*sm)); + return sm; } /** @@ -147,65 +147,73 @@ segment_manager_init (segment_manager_t * sm, first_seg_size = first_seg_size > 0 ? first_seg_size : default_segment_size; - if (sm->properties->use_private_segment == 0) - { - rv = session_manager_add_first_segment (sm, first_seg_size); - if (rv) - { - clib_warning ("Failed to allocate segment"); - return rv; - } - } - else + rv = session_manager_add_first_segment (sm, first_seg_size); + if (rv) { - if (vec_len (private_segment_indices) == 0) - segment_manager_alloc_process_private_segment (properties); - ASSERT (vec_len (private_segment_indices)); - vec_append (sm->segment_indices, private_segment_indices); + clib_warning ("Failed to allocate segment"); + return rv; } clib_spinlock_init (&sm->lockp); return 0; } -void -segment_manager_first_segment_maybe_del (segment_manager_t * sm) +u8 +segment_manager_has_fifos (segment_manager_t * sm) { - svm_fifo_segment_private_t *fifo_segment; - - /* If the first semgment has no fifos, then delete the 1st segment - */ - fifo_segment = svm_fifo_get_segment (sm->segment_indices[0]); - if (!svm_fifo_segment_has_fifos (fifo_segment)) + svm_fifo_segment_private_t *segment; + /* Weird, but handle it */ + if (vec_len (sm->segment_indices) == 0) + return 0; + if (vec_len (sm->segment_indices) == 1) { - clib_spinlock_lock (&sm->lockp); - svm_fifo_segment_delete (fifo_segment); - vec_del1 (sm->segment_indices, 0); - clib_spinlock_unlock (&sm->lockp); + segment = svm_fifo_segment_get_segment (sm->segment_indices[0]); + if (svm_fifo_segment_num_fifos (segment) == 0) + return 0; } + if (CLIB_DEBUG) + { + svm_fifo_segment_private_t *segment; + int i; + for (i = 1; i < vec_len (sm->segment_indices); i++) + { + segment = svm_fifo_segment_get_segment (sm->segment_indices[i]); + if (!svm_fifo_segment_has_fifos (segment)) + clib_warning ("segment has no fifos!"); + } + } + return 1; } - /** - * Removes segment manager. - * - * Since the fifos allocated in the segment keep backpointers to the sessions - * prior to removing the segment, we call session disconnect. This - * subsequently propages into transport. +static void +segment_manager_del_segment (segment_manager_t * sm, u32 segment_index) +{ + svm_fifo_segment_private_t *fifo_segment; + u32 svm_segment_index; + clib_spinlock_lock (&sm->lockp); + svm_segment_index = sm->segment_indices[segment_index]; + fifo_segment = svm_fifo_segment_get_segment (svm_segment_index); + svm_fifo_segment_delete (fifo_segment); + vec_del1 (sm->segment_indices, segment_index); + clib_spinlock_unlock (&sm->lockp); +} + +/** + * Initiate disconnects for all sessions 'owned' by a segment manager */ void -segment_manager_del (segment_manager_t * sm) +segment_manager_del_sessions (segment_manager_t * sm) { int j; svm_fifo_segment_private_t *fifo_segment; + svm_fifo_t *fifo; + ASSERT (vec_len (sm->segment_indices)); /* Across all fifo segments used by the server */ for (j = 0; j < vec_len (sm->segment_indices); j++) { - svm_fifo_t *fifo; - - /* Vector of fifos allocated in the segment */ - fifo_segment = svm_fifo_get_segment (sm->segment_indices[j]); + fifo_segment = svm_fifo_segment_get_segment (sm->segment_indices[j]); fifo = svm_fifo_segment_get_fifo_list (fifo_segment); /* @@ -220,14 +228,17 @@ segment_manager_del (segment_manager_t * sm) session_index = fifo->master_session_index; thread_index = fifo->master_thread_index; - session = stream_session_get (session_index, thread_index); /* Instead of directly removing the session call disconnect */ - session->session_state = SESSION_STATE_CLOSED; - session_send_session_evt_to_thread (stream_session_handle (session), - FIFO_EVENT_DISCONNECT, - thread_index); + if (session->session_state != SESSION_STATE_CLOSED) + { + session->session_state = SESSION_STATE_CLOSED; + session_send_session_evt_to_thread (stream_session_handle + (session), + FIFO_EVENT_DISCONNECT, + thread_index); + } fifo = fifo->next; } @@ -235,27 +246,51 @@ segment_manager_del (segment_manager_t * sm) * sessions if the segment can be removed. */ } +} - segment_manager_first_segment_maybe_del (sm); +/** + * Removes segment manager. + * + * Since the fifos allocated in the segment keep backpointers to the sessions + * prior to removing the segment, we call session disconnect. This + * subsequently propages into transport. + */ +void +segment_manager_del (segment_manager_t * sm) +{ + ASSERT (vec_len (sm->segment_indices) <= 1); + if (vec_len (sm->segment_indices)) + { + /* The first segment in the first segment manager is not removed when + * all fifos are removed. It can only be removed when the manager is + * explicitly deleted/detached by the app. */ + if (CLIB_DEBUG) + { + svm_fifo_segment_private_t *fifo_segment; + fifo_segment = + svm_fifo_segment_get_segment (sm->segment_indices[0]); + ASSERT (!svm_fifo_segment_has_fifos (fifo_segment)); + } + segment_manager_del_segment (sm, 0); + } clib_spinlock_free (&sm->lockp); + if (CLIB_DEBUG) + memset (sm, 0xfe, sizeof (*sm)); pool_put (segment_managers, sm); } -static int -segment_manager_notify_app_seg_add (segment_manager_t * sm, - u32 fifo_segment_index) +void +segment_manager_init_del (segment_manager_t * sm) { - application_t *app = application_get (sm->app_index); - u32 seg_size = 0; - u8 *seg_name; - - /* Send an API message to the external app, to map new segment */ - ASSERT (app->cb_fns.add_segment_callback); - - segment_manager_get_segment_info (fifo_segment_index, &seg_name, &seg_size); - return app->cb_fns.add_segment_callback (app->api_client_index, seg_name, - seg_size); + if (segment_manager_has_fifos (sm)) + segment_manager_del_sessions (sm); + else + { + ASSERT (!sm->first_is_protected + || sm->app_index == SEGMENT_MANAGER_INVALID_APP_INDEX); + segment_manager_del (sm); + } } int @@ -280,16 +315,14 @@ again: for (i = 0; i < vec_len (sm->segment_indices); i++) { *fifo_segment_index = sm->segment_indices[i]; - fifo_segment = svm_fifo_get_segment (*fifo_segment_index); + fifo_segment = svm_fifo_segment_get_segment (*fifo_segment_index); - /* FC: cleanup, make sure sm->properties->xxx_fifo_size always set */ fifo_size = sm->properties->rx_fifo_size; fifo_size = (fifo_size == 0) ? default_fifo_size : fifo_size; *server_rx_fifo = svm_fifo_segment_alloc_fifo (fifo_segment, fifo_size, FIFO_SEGMENT_RX_FREELIST); - /* FC: cleanup, make sure sm->properties->xxx_fifo_size always set */ fifo_size = sm->properties->tx_fifo_size; fifo_size = (fifo_size == 0) ? default_fifo_size : fifo_size; *server_tx_fifo = @@ -327,7 +360,7 @@ again: { if (added_a_segment) { - clib_warning ("added a segment, still cant allocate a fifo"); + clib_warning ("added a segment, still can't allocate a fifo"); clib_spinlock_unlock (&sm->lockp); return SESSION_ERROR_NEW_SEG_NO_SPACE; } @@ -357,7 +390,8 @@ again: clib_spinlock_unlock (&sm->lockp); if (added_a_segment) - return segment_manager_notify_app_seg_add (sm, *fifo_segment_index); + return application_add_segment_notify (sm->app_index, + *fifo_segment_index); return 0; } @@ -368,32 +402,49 @@ segment_manager_dealloc_fifos (u32 svm_segment_index, svm_fifo_t * rx_fifo, { segment_manager_t *sm; svm_fifo_segment_private_t *fifo_segment; + u32 i, segment_index = ~0; + u8 is_first; sm = segment_manager_get_if_valid (rx_fifo->segment_manager); /* It's possible to have no segment manager if the session was removed - * as result of a detach */ + * as result of a detach. */ if (!sm) return; - fifo_segment = svm_fifo_get_segment (svm_segment_index); + fifo_segment = svm_fifo_segment_get_segment (svm_segment_index); svm_fifo_segment_free_fifo (fifo_segment, rx_fifo, FIFO_SEGMENT_RX_FREELIST); svm_fifo_segment_free_fifo (fifo_segment, tx_fifo, FIFO_SEGMENT_TX_FREELIST); - /* Don't try to delete process-private segments */ - if (sm->properties->private_segment_count > 0) - return; - - /* Remove segment only if it holds no fifos and not the first */ - if (sm->segment_indices[0] != svm_segment_index - && !svm_fifo_segment_has_fifos (fifo_segment)) + /* + * Try to remove svm segment if it has no fifos. This can be done only if + * the segment is not the first in the segment manager or if it is first + * and it is not protected. Moreover, if the segment is first and the app + * has detached from the segment manager, remove the segment manager. + */ + if (!svm_fifo_segment_has_fifos (fifo_segment)) { - clib_spinlock_lock (&sm->lockp); - svm_fifo_segment_delete (fifo_segment); - vec_del1 (sm->segment_indices, svm_segment_index); - clib_spinlock_unlock (&sm->lockp); + is_first = sm->segment_indices[0] == svm_segment_index; + + /* Remove segment if it holds no fifos or first but not protected */ + if (!is_first || !sm->first_is_protected) + { + /* Find the segment manager segment index */ + for (i = 0; i < vec_len (sm->segment_indices); i++) + if (sm->segment_indices[i] == svm_segment_index) + { + segment_index = i; + break; + } + ASSERT (segment_index != (u32) ~ 0); + segment_manager_del_segment (sm, segment_index); + } + + /* Remove segment manager if no sessions and detached from app */ + if (sm->app_index == SEGMENT_MANAGER_INVALID_APP_INDEX && is_first) + segment_manager_del (sm); } } @@ -410,14 +461,14 @@ segment_manager_alloc_queue (segment_manager_t * sm, u32 queue_size) ASSERT (sm->segment_indices != 0); - segment = svm_fifo_get_segment (sm->segment_indices[0]); + segment = svm_fifo_segment_get_segment (sm->segment_indices[0]); sh = segment->ssvm.sh; oldheap = ssvm_push_heap (sh); - q = - unix_shared_memory_queue_init (queue_size, sizeof (session_fifo_event_t), - 0 /* consumer pid */ , 0 - /* signal when queue non-empty */ ); + q = unix_shared_memory_queue_init (queue_size, + sizeof (session_fifo_event_t), + 0 /* consumer pid */ , + 0 /* signal when queue non-empty */ ); ssvm_pop_heap (oldheap); return q; } @@ -435,7 +486,7 @@ segment_manager_dealloc_queue (segment_manager_t * sm, ASSERT (sm->segment_indices != 0); - segment = svm_fifo_get_segment (sm->segment_indices[0]); + segment = svm_fifo_segment_get_segment (sm->segment_indices[0]); sh = segment->ssvm.sh; oldheap = ssvm_push_heap (sh); @@ -443,6 +494,90 @@ segment_manager_dealloc_queue (segment_manager_t * sm, ssvm_pop_heap (oldheap); } +static clib_error_t * +segment_manager_show_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + svm_fifo_segment_private_t *segments, *seg; + segment_manager_t *sm; + u8 show_segments = 0, verbose = 0, *name; + uword address; + u64 size; + u32 fifos; + mheap_t *heap_header; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "segments")) + show_segments = 1; + else if (unformat (input, "verbose")) + verbose = 1; + else + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + } + vlib_cli_output (vm, "%d segment managers allocated", + pool_elts (segment_managers)); + if (verbose && pool_elts (segment_managers)) + { + vlib_cli_output (vm, "%-10s%=15s%=12s", "Index", "App Index", + "Segments"); + + /* *INDENT-OFF* */ + pool_foreach (sm, segment_managers, ({ + vlib_cli_output (vm, "%-10d%=15d%=12d", segment_manager_index(sm), + sm->app_index, vec_len (sm->segment_indices)); + })); + /* *INDENT-ON* */ + + } + if (show_segments) + { + segments = svm_fifo_segment_segments_pool (); + vlib_cli_output (vm, "%d svm fifo segments allocated", + pool_elts (segments)); + vlib_cli_output (vm, "%-20s%=12s%=12s%=15s", "Name", "Size (M)", + "Fifos", "Address"); + + /* *INDENT-OFF* */ + pool_foreach (seg, segments, ({ + if (seg->h->flags & FIFO_SEGMENT_F_IS_PRIVATE) + { + address = pointer_to_uword (seg->ssvm.sh->heap); + if (seg->h->flags & FIFO_SEGMENT_F_IS_MAIN_HEAP) + name = format (0, "main heap"); + else + name = format (0, "private heap"); + heap_header = mheap_header (seg->ssvm.sh->heap); + size = heap_header->max_size; + } + else + { + address = seg->ssvm.sh->ssvm_va; + size = seg->ssvm.ssvm_size; + name = seg->ssvm.sh->name; + } + fifos = svm_fifo_segment_num_fifos (seg); + vlib_cli_output (vm, "%-20s%=12u%=12u%=15x", name, size << 20, fifos, + address); + if (seg->h->flags & FIFO_SEGMENT_F_IS_PRIVATE) + vec_free (name); + })); + /* *INDENT-ON* */ + + } + return 0; +} + + /* *INDENT-OFF* */ +VLIB_CLI_COMMAND (segment_manager_show_command, static) = +{ + .path = "show segment-manager", + .short_help = "show segment-manager [segments]", + .function = segment_manager_show_fn, +}; +/* *INDENT-ON* */ + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/session/segment_manager.h b/src/vnet/session/segment_manager.h index 41abeb22..6e5b8989 100644 --- a/src/vnet/session/segment_manager.h +++ b/src/vnet/session/segment_manager.h @@ -55,23 +55,25 @@ typedef struct _segment_manager /** Owner app index */ u32 app_index; - /** Pointer to manager properties. Could be shared among all of - * an app's segment managers s*/ + /** + * Pointer to manager properties. Could be shared among all of + * an app's segment managers s + */ segment_manager_properties_t *properties; + + /** + * First segment should not be deleted unless segment manger is deleted. + * This also indicates that the segment manager is the first to have been + * allocated for the app. + */ + u8 first_is_protected; } segment_manager_t; +#define SEGMENT_MANAGER_INVALID_APP_INDEX ((u32) ~0) + /** Pool of segment managers */ extern segment_manager_t *segment_managers; -always_inline segment_manager_t * -segment_manager_new () -{ - segment_manager_t *sm; - pool_get (segment_managers, sm); - memset (sm, 0, sizeof (*sm)); - return sm; -} - always_inline segment_manager_t * segment_manager_get (u32 index) { @@ -92,6 +94,7 @@ segment_manager_index (segment_manager_t * sm) return sm - segment_managers; } +segment_manager_t *segment_manager_new (); int segment_manager_init (segment_manager_t * sm, segment_manager_properties_t * properties, @@ -100,9 +103,11 @@ segment_manager_init (segment_manager_t * sm, void segment_manager_get_segment_info (u32 index, u8 ** name, u32 * size); int session_manager_add_first_segment (segment_manager_t * sm, u32 segment_size); -void segment_manager_first_segment_maybe_del (segment_manager_t * sm); int session_manager_add_segment (segment_manager_t * sm); +void segment_manager_del_sessions (segment_manager_t * sm); void segment_manager_del (segment_manager_t * sm); +void segment_manager_init_del (segment_manager_t * sm); +u8 segment_manager_has_fifos (segment_manager_t * sm); int segment_manager_alloc_session_fifos (segment_manager_t * sm, svm_fifo_t ** server_rx_fifo, diff --git a/src/vnet/session/session.c b/src/vnet/session/session.c index 6fe99047..ee22ccbe 100644 --- a/src/vnet/session/session.c +++ b/src/vnet/session/session.c @@ -457,7 +457,10 @@ stream_session_connect_notify (transport_connection_t * tc, u8 is_fail) /* Get the app's index from the handle we stored when opening connection * and the opaque (api_context for external apps) from transport session * index*/ - app = application_get (handle >> 32); + app = application_get_if_valid (handle >> 32); + if (!app) + return -1; + opaque = tc->s_index; if (!is_fail) @@ -562,9 +565,7 @@ stream_session_delete_notify (transport_connection_t * tc) /* App might've been removed already */ s = stream_session_get_if_valid (tc->s_index, tc->thread_index); if (!s) - { - return; - } + return; stream_session_delete (s); } diff --git a/src/vnet/session/session_cli.c b/src/vnet/session/session_cli.c index f60048f1..028dc9d8 100755 --- a/src/vnet/session/session_cli.c +++ b/src/vnet/session/session_cli.c @@ -64,7 +64,8 @@ format_stream_session (u8 * s, va_list * args) stream_session_get_index (ss)); if (ss->session_state == SESSION_STATE_READY - || ss->session_state == SESSION_STATE_ACCEPTING) + || ss->session_state == SESSION_STATE_ACCEPTING + || ss->session_state == SESSION_STATE_CLOSED) { s = format (s, "%U", tp_vft->format_connection, ss->connection_index, ss->thread_index, verbose); @@ -83,16 +84,6 @@ format_stream_session (u8 * s, va_list * args) s = format (s, "%-40U%v", tp_vft->format_half_open, ss->connection_index, str); } - else if (ss->session_state == SESSION_STATE_CLOSED) - { - s = - format (s, "[CL] %U", tp_vft->format_connection, ss->connection_index, - ss->thread_index, verbose); - if (verbose == 1) - s = format (s, "%v", str); - if (verbose > 1) - s = format (s, "%U", format_stream_session_fifos, ss, verbose); - } else { clib_warning ("Session in state: %d!", ss->session_state); @@ -284,9 +275,9 @@ show_session_command_fn (vlib_main_t * vm, unformat_input_t * input, { if (once_per_pool && verbose == 1) { - str = - format (str, "%-50s%-15s%-10s%-10s%-10s", "Connection", - "State", "Rx-f", "Tx-f", "S-idx"); + str = format (str, "%-50s%-15s%-10s%-10s%-10s", + "Connection", "State", "Rx-f", "Tx-f", + "S-idx"); vlib_cli_output (vm, "%v", str); vec_reset_length (str); once_per_pool = 0; diff --git a/src/vnet/session/session_node.c b/src/vnet/session/session_node.c index cd52742b..dec6d13c 100644 --- a/src/vnet/session/session_node.c +++ b/src/vnet/session/session_node.c @@ -394,7 +394,6 @@ session_tx_fifo_dequeue_and_snd (vlib_main_t * vm, vlib_node_runtime_t * node, always_inline stream_session_t * session_event_get_session (session_fifo_event_t * e, u8 thread_index) { - ASSERT (e->fifo->master_thread_index == thread_index); return stream_session_get_if_valid (e->fifo->master_session_index, thread_index); } @@ -643,6 +642,8 @@ skip_dequeue: break; case FIFO_EVENT_BUILTIN_RX: s0 = session_event_get_session (e0, my_thread_index); + if (PREDICT_FALSE (!s0)) + continue; svm_fifo_unset_event (s0->server_rx_fifo); app = application_get (s0->app_index); app->cb_fns.builtin_server_rx_callback (s0); diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c index 6b2b4759..0a826a52 100644 --- a/src/vnet/tcp/tcp.c +++ b/src/vnet/tcp/tcp.c @@ -316,8 +316,10 @@ tcp_connection_close (tcp_connection_t * tc) tcp_send_fin (tc); tc->state = TCP_STATE_LAST_ACK; break; + case TCP_STATE_FIN_WAIT_1: + break; default: - clib_warning ("shouldn't be here"); + clib_warning ("state: %u", tc->state); } TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc); @@ -836,6 +838,8 @@ format_tcp_connection (u8 * s, va_list * args) tcp_connection_t *tc = va_arg (*args, tcp_connection_t *); u32 verbose = va_arg (*args, u32); + if (!tc) + return s; s = format (s, "%-50U", format_tcp_connection_id, tc); if (verbose) { -- cgit 1.2.3-korg From 33e002b168a211b1d620f4fffbd3752c8f1f2129 Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Wed, 6 Sep 2017 01:20:02 -0400 Subject: Fix session connect_* api message handling. Change-Id: If7fd125989c90240de12953658d10007b9eb4f07 Signed-off-by: Dave Wallace --- extras/gdb/gdb_cmdfile.vcl_client | 6 +- extras/gdb/gdb_cmdfile.vcl_server | 6 +- src/uri/sock_test_server.c | 2 +- src/uri/uri_tcp_test.c | 4 +- src/uri/uri_udp_test.c | 8 +- src/uri/vppcom.c | 225 ++++++++++++++++++-------------------- src/vnet/session/session.api | 45 +++----- src/vnet/session/session.h | 22 ++++ src/vnet/session/session_api.c | 26 ++--- 9 files changed, 165 insertions(+), 179 deletions(-) (limited to 'src/uri/vppcom.c') diff --git a/extras/gdb/gdb_cmdfile.vcl_client b/extras/gdb/gdb_cmdfile.vcl_client index a622f958..9b43ed6a 100644 --- a/extras/gdb/gdb_cmdfile.vcl_client +++ b/extras/gdb/gdb_cmdfile.vcl_client @@ -1,10 +1,10 @@ -echo \n\n====== gdb_cmdfile.vppcom_client ======\n +echo \n\n====== gdb_cmdfile.vcl_client ======\n -# Here are some interesting vppcom breakpoints... +# Here are some interesting VCL breakpoints... # Uncomment them out to set during gdb init. # #b vppcom_session_connect #b vppcom_session_write #b vppcom_session_read #b vl_api_connect_sock_t_handler -#b vl_api_connect_sock_reply_t_handler +#b vl_api_connect_session_reply_t_handler diff --git a/extras/gdb/gdb_cmdfile.vcl_server b/extras/gdb/gdb_cmdfile.vcl_server index 8e441018..f3ce4fbc 100644 --- a/extras/gdb/gdb_cmdfile.vcl_server +++ b/extras/gdb/gdb_cmdfile.vcl_server @@ -1,10 +1,10 @@ -echo \n\n====== gdb_cmdfile.vppcom_server ======\n +echo \n\n====== gdb_cmdfile.vcl_server ======\n -# Here are some interesting vppcom breakpoints... +# Here are some interesting VCL breakpoints... # Uncomment them out to set during gdb init. # #b vppcom_session_accept #b vppcom_session_write #b vppcom_session_read #b vl_api_connect_sock_t_handler -#b vl_api_connect_sock_reply_t_handler +#b vl_api_connect_session_reply_t_handler diff --git a/src/uri/sock_test_server.c b/src/uri/sock_test_server.c index 52c60dc4..f703b177 100644 --- a/src/uri/sock_test_server.c +++ b/src/uri/sock_test_server.c @@ -345,7 +345,7 @@ main (int argc, char **argv) memset (&servaddr, 0, sizeof (servaddr)); servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htons (INADDR_ANY); + servaddr.sin_addr.s_addr = htonl (INADDR_ANY); servaddr.sin_port = htons (port); #ifdef VCL_TEST diff --git a/src/uri/uri_tcp_test.c b/src/uri/uri_tcp_test.c index f5fbbd23..cb297b55 100755 --- a/src/uri/uri_tcp_test.c +++ b/src/uri/uri_tcp_test.c @@ -526,7 +526,7 @@ client_rx_thread_fn (void *arg) static void -vl_api_connect_uri_reply_t_handler (vl_api_connect_uri_reply_t * mp) +vl_api_connect_session_reply_t_handler (vl_api_connect_session_reply_t * mp) { uri_tcp_test_main_t *utm = &uri_tcp_test_main; session_t *session; @@ -1122,7 +1122,7 @@ vl_api_disconnect_session_reply_t_handler (vl_api_disconnect_session_reply_t * _(BIND_URI_REPLY, bind_uri_reply) \ _(UNBIND_URI_REPLY, unbind_uri_reply) \ _(ACCEPT_SESSION, accept_session) \ -_(CONNECT_URI_REPLY, connect_uri_reply) \ +_(CONNECT_SESSION_REPLY, connect_session_reply) \ _(DISCONNECT_SESSION, disconnect_session) \ _(DISCONNECT_SESSION_REPLY, disconnect_session_reply) \ _(RESET_SESSION, reset_session) \ diff --git a/src/uri/uri_udp_test.c b/src/uri/uri_udp_test.c index aea4707c..f50ee688 100644 --- a/src/uri/uri_udp_test.c +++ b/src/uri/uri_udp_test.c @@ -518,7 +518,7 @@ vl_api_connect_uri_t_handler (vl_api_connect_uri_t * mp) svm_fifo_segment_create_args_t _a, *a = &_a; svm_fifo_segment_private_t *seg; unix_shared_memory_queue_t *client_q; - vl_api_connect_uri_reply_t *rmp; + vl_api_connect_session_reply_t *rmp; session_t *session = 0; int rv = 0; @@ -566,7 +566,7 @@ send_reply: rmp = vl_msg_api_alloc (sizeof (*rmp)); memset (rmp, 0, sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_CONNECT_URI_REPLY); + rmp->_vl_msg_id = ntohs (VL_API_CONNECT_SESSION_REPLY); rmp->context = mp->context; rmp->retval = ntohl (rv); rmp->segment_name_length = vec_len (a->segment_name); @@ -674,7 +674,7 @@ vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp) } static void -vl_api_connect_uri_reply_t_handler (vl_api_connect_uri_reply_t * mp) +vl_api_connect_session_reply_t_handler (vl_api_connect_session_reply_t * mp) { uri_udp_test_main_t *utm = &uri_udp_test_main; @@ -727,7 +727,7 @@ vl_api_connect_uri_reply_t_handler (vl_api_connect_uri_reply_t * mp) #define foreach_uri_msg \ _(BIND_URI_REPLY, bind_uri_reply) \ _(CONNECT_URI, connect_uri) \ -_(CONNECT_URI_REPLY, connect_uri_reply) \ +_(CONNECT_SESSION_REPLY, connect_session_reply) \ _(UNBIND_URI_REPLY, unbind_uri_reply) \ _(ACCEPT_SESSION, accept_session) \ _(DISCONNECT_SESSION, disconnect_session) \ diff --git a/src/uri/vppcom.c b/src/uri/vppcom.c index c41acd54..aec1295f 100644 --- a/src/uri/vppcom.c +++ b/src/uri/vppcom.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Cisco and/or its affiliates. + * Copyright (c) 2017 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this * You may obtain a copy of the License at: @@ -76,7 +76,7 @@ typedef struct svm_fifo_t *server_tx_fifo; u32 sm_seg_index; u64 vpp_session_handle; - unix_shared_memory_queue_t *event_queue; + unix_shared_memory_queue_t *vpp_event_queue; /* Socket configuration state */ u8 is_server; @@ -682,7 +682,7 @@ vl_api_reset_session_t_handler (vl_api_reset_session_t * mp) } static void -vl_api_connect_sock_reply_t_handler (vl_api_connect_sock_reply_t * mp) +vl_api_connect_session_reply_t_handler (vl_api_connect_session_reply_t * mp) { vppcom_main_t *vcm = &vppcom_main; session_t *session; @@ -698,9 +698,9 @@ vl_api_connect_sock_reply_t_handler (vl_api_connect_sock_reply_t * mp) return; } - session_index = ntohl (mp->app_connect); + session_index = mp->context; if (VPPCOM_DEBUG > 1) - clib_warning ("[%d] app_connect = %d 0x%08x", vcm->my_pid, + clib_warning ("[%d] session_index = %d 0x%08x", vcm->my_pid, session_index, session_index); clib_spinlock_lock (&vcm->sessions_lockp); @@ -743,8 +743,8 @@ vl_api_connect_sock_reply_t_handler (vl_api_connect_sock_reply_t * mp) session = pool_elt_at_index (vcm->sessions, session_index); session->is_cut_thru = is_cut_thru; - session->event_queue = uword_to_pointer (mp->vpp_event_queue_address, - unix_shared_memory_queue_t *); + session->vpp_event_queue = uword_to_pointer (mp->vpp_event_queue_address, + unix_shared_memory_queue_t *); rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *); rx_fifo->client_session_index = session_index; @@ -773,13 +773,11 @@ vppcom_send_connect_sock (session_t * session, u32 session_index) memset (cmp, 0, sizeof (*cmp)); cmp->_vl_msg_id = ntohs (VL_API_CONNECT_SOCK); cmp->client_index = vcm->my_client_index; - cmp->context = htonl (0xfeedface); - cmp->app_connect = session_index; + cmp->context = session_index; if (VPPCOM_DEBUG > 1) - clib_warning ("[%d] session_index = %d 0x%08x, app_connect = %d 0x%08x", - vcm->my_pid, session_index, session_index, - cmp->app_connect, cmp->app_connect); + clib_warning ("[%d] session_index = %d 0x%08x", + vcm->my_pid, session_index, session_index); cmp->vrf = session->vrf; cmp->is_ip4 = session->is_ip4; @@ -991,8 +989,8 @@ vl_api_accept_session_t_handler (vl_api_accept_session_t * mp) session->server_rx_fifo = rx_fifo; session->server_tx_fifo = tx_fifo; - session->event_queue = uword_to_pointer (mp->vpp_event_queue_address, - unix_shared_memory_queue_t *); + session->vpp_event_queue = uword_to_pointer (mp->vpp_event_queue_address, + unix_shared_memory_queue_t *); session->state = STATE_ACCEPT; session->is_cut_thru = 0; session->port = ntohs (mp->port); @@ -1029,7 +1027,7 @@ vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp) u32 session_index; svm_fifo_segment_private_t *seg; unix_shared_memory_queue_t *client_q; - vl_api_connect_sock_reply_t *rmp; + vl_api_connect_session_reply_t *rmp; session_t *session = 0; int rv = 0; svm_fifo_t *rx_fifo; @@ -1119,7 +1117,7 @@ vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp) ssvm_lock_non_recursive (sh, 1); oldheap = ssvm_push_heap (sh); - event_q = session->event_queue = + event_q = session->vpp_event_queue = unix_shared_memory_queue_init (vcm->cfg.event_queue_size, sizeof (session_fifo_event_t), vcm->my_pid, 0 /* signal not sent */ ); @@ -1139,9 +1137,8 @@ send_reply: rmp = vl_msg_api_alloc (sizeof (*rmp)); memset (rmp, 0, sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_CONNECT_SOCK_REPLY); + rmp->_vl_msg_id = ntohs (VL_API_CONNECT_SESSION_REPLY); rmp->context = mp->context; - rmp->app_connect = htonl (mp->app_connect); rmp->retval = htonl (rv); rmp->segment_name_length = vec_len (a->segment_name); clib_memcpy (rmp->segment_name, a->segment_name, vec_len (a->segment_name)); @@ -1293,7 +1290,7 @@ _(BIND_SOCK_REPLY, bind_sock_reply) \ _(UNBIND_SOCK_REPLY, unbind_sock_reply) \ _(ACCEPT_SESSION, accept_session) \ _(CONNECT_SOCK, connect_sock) \ -_(CONNECT_SOCK_REPLY, connect_sock_reply) \ +_(CONNECT_SESSION_REPLY, connect_session_reply) \ _(DISCONNECT_SESSION, disconnect_session) \ _(DISCONNECT_SESSION_REPLY, disconnect_session_reply) \ _(RESET_SESSION, reset_session) \ @@ -1878,6 +1875,7 @@ vppcom_session_bind (uint32_t session_index, vppcom_endpt_t * ep) vppcom_main_t *vcm = &vppcom_main; session_t *session = 0; int rv; + ip46_address_t *ip46; if (!ep || !ep->ip) return VPPCOM_EINVAL; @@ -1898,8 +1896,9 @@ vppcom_session_bind (uint32_t session_index, vppcom_endpt_t * ep) session->vrf = ep->vrf; session->is_ip4 = ep->is_ip4; - memset (session->ip, 0, sizeof (*session->ip)); - clib_memcpy (session->ip, ep->ip, sizeof (session->ip)); + memset (session->ip, 0, sizeof (session->ip)); + ip46 = (ip46_address_t *) session->ip; + *ip46 = to_ip46 (!ep->is_ip4, ep->ip); session->port = ep->port; clib_spinlock_unlock (&vcm->sessions_lockp); @@ -1907,32 +1906,33 @@ vppcom_session_bind (uint32_t session_index, vppcom_endpt_t * ep) } int -vppcom_session_listen (uint32_t session_index, uint32_t q_len) +vppcom_session_listen (uint32_t listen_session_index, uint32_t q_len) { vppcom_main_t *vcm = &vppcom_main; - session_t *session = 0; + session_t *listen_session = 0; int rv; clib_spinlock_lock (&vcm->sessions_lockp); - rv = vppcom_session_at_index (session_index, &session); + rv = vppcom_session_at_index (listen_session_index, &listen_session); if (PREDICT_FALSE (rv)) { clib_spinlock_unlock (&vcm->sessions_lockp); if (VPPCOM_DEBUG > 0) clib_warning ("[%d] invalid session, sid (%d) has been closed!", - vcm->my_pid, session_index); + vcm->my_pid, listen_session_index); return rv; } if (VPPCOM_DEBUG > 0) - clib_warning ("[%d] sid %d", vcm->my_pid, session_index); + clib_warning ("[%d] sid %d", vcm->my_pid, listen_session_index); ASSERT (vcm->bind_session_index == ~0); - vcm->bind_session_index = session_index; - vppcom_send_bind_sock (session); + vcm->bind_session_index = listen_session_index; + vppcom_send_bind_sock (listen_session); clib_spinlock_unlock (&vcm->sessions_lockp); - rv = vppcom_wait_for_session_state_change (session_index, STATE_LISTEN, - vcm->cfg.session_timeout); + rv = + vppcom_wait_for_session_state_change (listen_session_index, STATE_LISTEN, + vcm->cfg.session_timeout); if (PREDICT_FALSE (rv)) { vcm->bind_session_index = ~0; @@ -1943,16 +1943,16 @@ vppcom_session_listen (uint32_t session_index, uint32_t q_len) } clib_spinlock_lock (&vcm->sessions_lockp); - rv = vppcom_session_at_index (session_index, &session); + rv = vppcom_session_at_index (listen_session_index, &listen_session); if (PREDICT_FALSE (rv)) { clib_spinlock_unlock (&vcm->sessions_lockp); if (VPPCOM_DEBUG > 0) clib_warning ("[%d] invalid session, sid (%d) has been closed!", - vcm->my_pid, session_index); + vcm->my_pid, listen_session_index); return rv; } - session->is_listen = 1; + listen_session->is_listen = 1; clib_spinlock_unlock (&vcm->sessions_lockp); clib_fifo_validate (vcm->client_session_index_fifo, q_len); @@ -1964,13 +1964,14 @@ vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep, double wait_for_time) { vppcom_main_t *vcm = &vppcom_main; - session_t *session = 0; + session_t *listen_session = 0; + session_t *client_session = 0; u32 client_session_index; int rv; f64 wait_for; clib_spinlock_lock (&vcm->sessions_lockp); - rv = vppcom_session_at_index (listen_session_index, &session); + rv = vppcom_session_at_index (listen_session_index, &listen_session); if (PREDICT_FALSE (rv)) { clib_spinlock_unlock (&vcm->sessions_lockp); @@ -1980,21 +1981,23 @@ vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep, return rv; } - if (session->state != STATE_LISTEN) + if (listen_session->state != STATE_LISTEN) { clib_spinlock_unlock (&vcm->sessions_lockp); if (VPPCOM_DEBUG > 0) clib_warning ("[%d] session not in listen state, state = %s", - vcm->my_pid, vppcom_session_state_str (session->state)); + vcm->my_pid, + vppcom_session_state_str (listen_session->state)); return VPPCOM_EBADFD; } - wait_for = session->is_nonblocking ? 0 : + wait_for = listen_session->is_nonblocking ? 0 : (wait_for_time < 0) ? vcm->cfg.accept_timeout : wait_for_time; if (VPPCOM_DEBUG > 0) - clib_warning ("[%d] sid %d, state %s (%d)", vcm->my_pid, + clib_warning ("[%d] sid %d: %s (%d)", vcm->my_pid, listen_session_index, - vppcom_session_state_str (session->state), session->state); + vppcom_session_state_str (listen_session->state), + listen_session->state); clib_spinlock_unlock (&vcm->sessions_lockp); while (1) @@ -2015,23 +2018,23 @@ vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep, clib_fifo_sub1 (vcm->client_session_index_fifo, client_session_index); - session = 0; clib_spinlock_lock (&vcm->sessions_lockp); - rv = vppcom_session_at_index (client_session_index, &session); + rv = vppcom_session_at_index (client_session_index, &client_session); ASSERT (rv == VPPCOM_OK); - ASSERT (session->is_server); + ASSERT (client_session->is_ip4 == listen_session->is_ip4); if (VPPCOM_DEBUG > 0) clib_warning ("[%d] Got a request: client sid %d", vcm->my_pid, client_session_index); - ep->vrf = session->vrf; - ep->is_cut_thru = session->is_cut_thru; - ep->is_ip4 = session->is_ip4; - ep->port = session->port; - memset (ep->ip, 0, sizeof (ip6_address_t)); - clib_memcpy (ep->ip, session->ip, sizeof (ip6_address_t)); - session->state = STATE_LISTEN; + ep->vrf = client_session->vrf; + ep->is_cut_thru = client_session->is_cut_thru; + ep->is_ip4 = client_session->is_ip4; + ep->port = client_session->port; + if (client_session->is_ip4) + clib_memcpy (ep->ip, client_session->ip, sizeof (ip4_address_t)); + else + clib_memcpy (ep->ip, client_session->ip, sizeof (ip6_address_t)); clib_spinlock_unlock (&vcm->sessions_lockp); return (int) client_session_index; } @@ -2066,6 +2069,7 @@ vppcom_session_connect (uint32_t session_index, vppcom_endpt_t * server_ep) session->vrf = server_ep->vrf; session->is_ip4 = server_ep->is_ip4; + memset (session->ip, 0, sizeof (session->ip)); ip46 = (ip46_address_t *) session->ip; *ip46 = to_ip46 (!server_ep->is_ip4, server_ep->ip); session->port = server_ep->port; @@ -2097,12 +2101,12 @@ vppcom_session_connect (uint32_t session_index, vppcom_endpt_t * server_ep) int vppcom_session_read (uint32_t session_index, void *buf, int n) { - session_fifo_event_t _e, *e = &_e; vppcom_main_t *vcm = &vppcom_main; session_t *session = 0; svm_fifo_t *rx_fifo; int n_read = 0; int rv; + int max_dequeue; char *fifo_str; ASSERT (buf); @@ -2118,100 +2122,62 @@ vppcom_session_read (uint32_t session_index, void *buf, int n) return rv; } - if (session->is_cut_thru) + if (session->state == STATE_DISCONNECT) { - rx_fifo = session->is_server ? session->server_rx_fifo : - session->server_tx_fifo; - fifo_str = session->is_server ? "server_rx_fifo" : "server_tx_fifo"; clib_spinlock_unlock (&vcm->sessions_lockp); - - n_read = svm_fifo_dequeue_nowait (rx_fifo, n, buf); - - if (n_read <= 0) - return VPPCOM_EAGAIN; - + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] sid (%d) has been closed by remote peer!", + vcm->my_pid, session_index); + return VPPCOM_ECONNRESET; } - else - { - rv = unix_shared_memory_queue_sub (session->event_queue, (u8 *) e, - 1 /* nowait */ ); - clib_spinlock_unlock (&vcm->sessions_lockp); - if (rv < 0) - return VPPCOM_EAGAIN; - - switch (e->event_type) - { - case FIFO_EVENT_APP_RX: - rx_fifo = e->fifo; - fifo_str = "app_rx_fifo"; - n_read = svm_fifo_dequeue_nowait (rx_fifo, n, buf); - break; - case FIFO_EVENT_DISCONNECT: - return VPPCOM_ECONNRESET; + rx_fifo = ((!session->is_cut_thru || session->is_server) ? + session->server_rx_fifo : session->server_tx_fifo); + fifo_str = ((!session->is_cut_thru || session->is_server) ? + "server_rx_fifo" : "server_tx_fifo"); + clib_spinlock_unlock (&vcm->sessions_lockp); - default: - if (VPPCOM_DEBUG > 0) - clib_warning ("[%d] unknown event type %d", vcm->my_pid, - e->event_type); - return VPPCOM_EAGAIN; - } - } + max_dequeue = (int) svm_fifo_max_dequeue (rx_fifo); + n_read = svm_fifo_dequeue_nowait (rx_fifo, clib_min (n, max_dequeue), buf); if (VPPCOM_DEBUG > 2) clib_warning ("[%d] sid %d, read %d bytes from %s (%p)", vcm->my_pid, session_index, n_read, fifo_str, rx_fifo); - return n_read; + + return (n_read <= 0) ? VPPCOM_EAGAIN : n_read; } static inline int vppcom_session_read_ready (session_t * session, u32 session_index) { - session_fifo_event_t _e, *e = &_e; vppcom_main_t *vcm = &vppcom_main; svm_fifo_t *rx_fifo; - int rv; int ready = 0; /* Assumes caller has acquired spinlock: vcm->sessions_lockp */ - if (session->is_cut_thru) + if (session->state == STATE_DISCONNECT) { - rx_fifo = session->is_server ? session->server_rx_fifo : - session->server_tx_fifo; - - ready = svm_fifo_max_dequeue (rx_fifo); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] sid (%d) has been closed by remote peer!", + vcm->my_pid, session_index); + return VPPCOM_ECONNRESET; } - else if (session->is_listen) + + if (session->is_listen) ready = clib_fifo_elts (vcm->client_session_index_fifo); else { - rv = unix_shared_memory_queue_sub (vcm->app_event_queue, (u8 *) e, - 1 /* nowait */ ); - if (rv >= 0) - { - switch (e->event_type) - { - case FIFO_EVENT_APP_RX: - rx_fifo = e->fifo; - ready = svm_fifo_max_dequeue (rx_fifo); - break; + rx_fifo = ((!session->is_cut_thru || session->is_server) ? + session->server_rx_fifo : session->server_tx_fifo); - case FIFO_EVENT_DISCONNECT: - return VPPCOM_ECONNRESET; - - default: - clib_warning ("[%d] unknown event type %d", vcm->my_pid, - e->event_type); - } - } + ready = svm_fifo_max_dequeue (rx_fifo); } - if (VPPCOM_DEBUG > 2) + if (VPPCOM_DEBUG > 3) clib_warning ("[%d] sid %d, peek %s (%p), ready = %d", vcm->my_pid, session_index, session->is_server ? "server_rx_fifo" : "server_tx_fifo", rx_fifo, ready); - return ready; } @@ -2240,10 +2206,20 @@ vppcom_session_write (uint32_t session_index, void *buf, int n) return rv; } + if (session->state == STATE_DISCONNECT) + { + clib_spinlock_unlock (&vcm->sessions_lockp); + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] sid (%d) has been closed by remote peer!", + vcm->my_pid, session_index); + return VPPCOM_ECONNRESET; + } + tx_fifo = ((!session->is_cut_thru || session->is_server) ? session->server_tx_fifo : session->server_rx_fifo); fifo_str = ((!session->is_cut_thru || session->is_server) ? "server_tx_fifo" : "server_rx_fifo"); + is_nonblocking = session->is_nonblocking; clib_spinlock_unlock (&vcm->sessions_lockp); @@ -2254,7 +2230,7 @@ vppcom_session_write (uint32_t session_index, void *buf, int n) while (!is_nonblocking && (rv <= 0)); /* If event wasn't set, add one */ - if ((rv > 0) && svm_fifo_set_event (tx_fifo)) + if (!session->is_cut_thru && (rv > 0) && svm_fifo_set_event (tx_fifo)) { int rval; @@ -2273,7 +2249,7 @@ vppcom_session_write (uint32_t session_index, void *buf, int n) vcm->my_pid, session_index); return rval; } - q = session->event_queue; + q = session->vpp_event_queue; clib_spinlock_unlock (&vcm->sessions_lockp); ASSERT (q); unix_shared_memory_queue_add (q, (u8 *) & evt, @@ -2292,19 +2268,28 @@ vppcom_session_write_ready (session_t * session, u32 session_index) { vppcom_main_t *vcm = &vppcom_main; svm_fifo_t *tx_fifo; + char *fifo_str; int rv; /* Assumes caller has acquired spinlock: vcm->sessions_lockp */ + if (session->state == STATE_DISCONNECT) + { + if (VPPCOM_DEBUG > 0) + clib_warning ("[%d] sid (%d) has been closed by remote peer!", + vcm->my_pid, session_index); + return VPPCOM_ECONNRESET; + } + tx_fifo = ((!session->is_cut_thru || session->is_server) ? session->server_tx_fifo : session->server_rx_fifo); + fifo_str = ((!session->is_cut_thru || session->is_server) ? + "server_tx_fifo" : "server_rx_fifo"); rv = svm_fifo_max_enqueue (tx_fifo); - if (VPPCOM_DEBUG > 2) + if (VPPCOM_DEBUG > 3) clib_warning ("[%d] sid %d, peek %s (%p), ready = %d", vcm->my_pid, - session_index, - session->is_server ? "server_tx_fifo" : "server_rx_fifo", - tx_fifo, rv); + session_index, fifo_str, tx_fifo, rv); return rv; } diff --git a/src/vnet/session/session.api b/src/vnet/session/session.api index e01cc75e..30d2ae96 100644 --- a/src/vnet/session/session.api +++ b/src/vnet/session/session.api @@ -105,7 +105,7 @@ autoreply define unbind_uri { @param client_queue_address - binary API client queue address. Used by local server when connect was redirected. */ -define connect_uri { +autoreply define connect_uri { u32 client_index; u32 context; u8 uri[128]; @@ -113,31 +113,6 @@ define connect_uri { u64 options[16]; }; -/** \brief vpp->client, connect reply - @param context - sender context, to match reply w/ request - @param retval - return code for the request - @param handle - session handle - @param server_rx_fifo - rx (vpp -> vpp-client) fifo address - @param server_tx_fifo - tx (vpp-client -> vpp) fifo address - @param vpp_event_queue_address - vpp's event queue address - @param segment_size - size of segment to be attached. Only for redirects. - @param segment_name_length - non-zero if the client needs to attach to - the fifo segment. This should only happen - if session was redirected. - @param segment_name - set if the client needs to attach to the segment -*/ -define connect_uri_reply { - u32 context; - i32 retval; - u64 handle; - u64 server_rx_fifo; - u64 server_tx_fifo; - u64 vpp_event_queue_address; - u32 segment_size; - u8 segment_name_length; - u8 segment_name[128]; -}; - /** \brief vpp->client, accept this session @param context - sender context, to match reply w/ request @param listener_handle - tells client which listener this pertains to @@ -273,10 +248,9 @@ autoreply define unbind_sock { used to perform redirects @param options - socket options, fifo sizes, etc. when doing redirects */ -define connect_sock { +autoreply define connect_sock { u32 client_index; u32 context; - u32 app_connect; u32 vrf; u8 is_ip4; u8 ip[16]; @@ -305,11 +279,19 @@ define bind_sock_reply { u8 segment_name[128]; }; -/** \brief vpp/server->client, connect reply +/* Dummy connect message -- needed to satisfy api generators +* +* NEVER USED, doxygen tags elided on purpose. +*/ +define connect_session { + u32 client_index; + u32 context; +}; + +/** \brief vpp/server->client, connect reply -- used for all connect_* messages @param context - sender context, to match reply w/ request @param retval - return code for the request @param handle - connection handle - @param app_connect - application connection id from connect msg @param server_rx_fifo - rx (vpp -> vpp-client) fifo address @param server_tx_fifo - tx (vpp-client -> vpp) fifo address @param vpp_event_queue_address - vpp's event queue address @@ -318,11 +300,10 @@ define bind_sock_reply { the fifo segment @param segment_name - set if the client needs to attach to the segment */ -define connect_sock_reply { +define connect_session_reply { u32 context; i32 retval; u64 handle; - u32 app_connect; u64 server_rx_fifo; u64 server_tx_fifo; u64 vpp_event_queue_address; diff --git a/src/vnet/session/session.h b/src/vnet/session/session.h index 74d82a40..83addec2 100644 --- a/src/vnet/session/session.h +++ b/src/vnet/session/session.h @@ -38,6 +38,28 @@ typedef enum FIFO_EVENT_RPC, } fifo_event_type_t; +static inline const char * +fifo_event_type_str (fifo_event_type_t et) +{ + switch (et) + { + case FIFO_EVENT_APP_RX: + return "FIFO_EVENT_APP_RX"; + case FIFO_EVENT_APP_TX: + return "FIFO_EVENT_APP_TX"; + case FIFO_EVENT_TIMEOUT: + return "FIFO_EVENT_TIMEOUT"; + case FIFO_EVENT_DISCONNECT: + return "FIFO_EVENT_DISCONNECT"; + case FIFO_EVENT_BUILTIN_RX: + return "FIFO_EVENT_BUILTIN_RX"; + case FIFO_EVENT_RPC: + return "FIFO_EVENT_RPC"; + default: + return "UNKNOWN FIFO EVENT"; + } +} + #define foreach_session_input_error \ _(NO_SESSION, "No session drops") \ _(NO_LISTENER, "No listener for dst port drops") \ diff --git a/src/vnet/session/session_api.c b/src/vnet/session/session_api.c index 6bee3e27..60d9b4de 100755 --- a/src/vnet/session/session_api.c +++ b/src/vnet/session/session_api.c @@ -155,7 +155,7 @@ int send_session_connected_callback (u32 app_index, u32 api_context, stream_session_t * s, u8 is_fail) { - vl_api_connect_uri_reply_t *mp; + vl_api_connect_session_reply_t *mp; unix_shared_memory_queue_t *q; application_t *app; unix_shared_memory_queue_t *vpp_queue; @@ -167,7 +167,7 @@ send_session_connected_callback (u32 app_index, u32 api_context, return -1; mp = vl_msg_api_alloc (sizeof (*mp)); - mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_CONNECT_URI_REPLY); + mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_CONNECT_SESSION_REPLY); mp->context = api_context; if (!is_fail) { @@ -415,7 +415,7 @@ done: static void vl_api_connect_uri_t_handler (vl_api_connect_uri_t * mp) { - vl_api_connect_uri_reply_t *rmp; + vl_api_connect_session_reply_t *rmp; vnet_connect_args_t _a, *a = &_a; application_t *app; int rv; @@ -447,7 +447,7 @@ vl_api_connect_uri_t_handler (vl_api_connect_uri_t * mp) done: /* *INDENT-OFF* */ - REPLY_MACRO (VL_API_CONNECT_URI_REPLY); + REPLY_MACRO (VL_API_CONNECT_SESSION_REPLY); /* *INDENT-ON* */ } @@ -593,11 +593,11 @@ vl_api_bind_sock_t_handler (vl_api_bind_sock_t * mp) app = application_lookup (mp->client_index); if (app) { + ip46_address_t *ip46 = (ip46_address_t *) mp->ip; + memset (a, 0, sizeof (*a)); - clib_memcpy (&a->tep.ip, mp->ip, (mp->is_ip4 ? - sizeof (ip4_address_t) : - sizeof (ip6_address_t))); a->tep.is_ip4 = mp->is_ip4; + a->tep.ip = *ip46; a->tep.port = mp->port; a->tep.vrf = mp->vrf; a->app_index = app->index; @@ -637,7 +637,7 @@ done: static void vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp) { - vl_api_connect_sock_reply_t *rmp; + vl_api_connect_session_reply_t *rmp; vnet_connect_args_t _a, *a = &_a; application_t *app; int rv; @@ -652,16 +652,14 @@ vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp) if (app) { unix_shared_memory_queue_t *client_q; - u8 *ip = mp->is_ip4 ? (u8 *) & a->tep.ip.ip4 : (u8 *) & a->tep.ip; + ip46_address_t *ip46 = (ip46_address_t *) mp->ip; client_q = vl_api_client_index_to_input_queue (mp->client_index); mp->client_queue_address = pointer_to_uword (client_q); a->tep.is_ip4 = mp->is_ip4; + a->tep.ip = *ip46; a->tep.port = mp->port; - - clib_memcpy (ip, mp->ip, - (mp->is_ip4 ? sizeof (ip4_address_t) : - sizeof (ip6_address_t))); + a->tep.vrf = mp->vrf; a->api_context = mp->context; a->app_index = app->index; a->proto = mp->proto; @@ -679,7 +677,7 @@ vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp) /* Got some error, relay it */ done: - REPLY_MACRO (VL_API_CONNECT_SOCK_REPLY); + REPLY_MACRO (VL_API_CONNECT_SESSION_REPLY); } static clib_error_t * -- cgit 1.2.3-korg From ab7b8d93cf1098970bc17fb4937376bb1ff33a21 Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Thu, 7 Sep 2017 07:40:13 -0400 Subject: Fixes for issues reported by Coverity (VPP-972) Change-Id: I25238debb7081b4467aec4620dfdef33fbef3295 Signed-off-by: Chris Luke --- src/svm/svm_fifo.c | 2 +- src/uri/sock_test_client.c | 2 ++ src/uri/sock_test_server.c | 12 +++++++++--- src/uri/vppcom.c | 17 ++++++++--------- src/vlib/unix/main.c | 8 ++++---- src/vnet/ipsec/ikev2.c | 11 ++++++++++- src/vppinfra/socket.c | 16 ++++++++++++++-- 7 files changed, 48 insertions(+), 20 deletions(-) (limited to 'src/uri/vppcom.c') diff --git a/src/svm/svm_fifo.c b/src/svm/svm_fifo.c index 8fe82f56..42eb1ee8 100644 --- a/src/svm/svm_fifo.c +++ b/src/svm/svm_fifo.c @@ -443,7 +443,7 @@ ooo_segment_try_collect (svm_fifo_t * f, u32 n_bytes_enqueued) } } - ASSERT (bytes >= 0 && bytes <= f->nitems); + ASSERT (bytes <= f->nitems); return bytes; } diff --git a/src/uri/sock_test_client.c b/src/uri/sock_test_client.c index 4319f01b..ab8e5a0e 100644 --- a/src/uri/sock_test_client.c +++ b/src/uri/sock_test_client.c @@ -895,6 +895,8 @@ main (int argc, char **argv) case 'w': fprintf (stderr, "ERROR: Option -%c requires an argument.\n", optopt); + break; + default: if (isprint (optopt)) fprintf (stderr, "ERROR: Unknown option `-%c'.\n", optopt); diff --git a/src/uri/sock_test_server.c b/src/uri/sock_test_server.c index f703b177..29adea25 100644 --- a/src/uri/sock_test_server.c +++ b/src/uri/sock_test_server.c @@ -514,9 +514,15 @@ main (int argc, char **argv) continue; } - else if (strlen ((char *) conn->buf)) - printf ("\nSERVER (fd %d): RX (%d bytes) - '%s'\n", - conn->fd, rx_bytes, conn->buf); + else if (((char *) conn->buf)[0] != 0) + { + // If it looks vaguely like a string, make sure it's terminated + ((char *) conn->buf)[rx_bytes < + conn->buf_size ? rx_bytes : + conn->buf_size - 1] = 0; + printf ("\nSERVER (fd %d): RX (%d bytes) - '%s'\n", + conn->fd, rx_bytes, conn->buf); + } } else // rx_bytes < 0 { diff --git a/src/uri/vppcom.c b/src/uri/vppcom.c index aec1295f..aa307f1d 100644 --- a/src/uri/vppcom.c +++ b/src/uri/vppcom.c @@ -1369,23 +1369,18 @@ vppcom_cfg_heapsize (char *conf_fname) argc++; char **tmp = realloc (argv, argc * sizeof (char *)); if (tmp == NULL) - { - fclose (fp); - goto defaulted; - } + goto defaulted; argv = tmp; arg = strndup (p, 1024); if (arg == NULL) - { - fclose (fp); - goto defaulted; - } + goto defaulted; argv[argc - 1] = arg; p = strtok (NULL, " \t\n"); } } fclose (fp); + fp = NULL; char **tmp = realloc (argv, (argc + 1) * sizeof (char *)); if (tmp == NULL) @@ -1438,6 +1433,10 @@ vppcom_cfg_heapsize (char *conf_fname) } defaulted: + if (fp != NULL) + fclose (fp); + if (argv != NULL) + free (argv); if (!clib_mem_init (0, vcl_cfg->heapsize)) clib_warning ("[%d] vppcom heap allocation failure!", vcm->my_pid); else if (VPPCOM_DEBUG > 0) @@ -1687,7 +1686,7 @@ input_done: unformat_free (input); file_done: - if (fd > 0) + if (fd >= 0) close (fd); } diff --git a/src/vlib/unix/main.c b/src/vlib/unix/main.c index c90e1331..3a92b2e3 100644 --- a/src/vlib/unix/main.c +++ b/src/vlib/unix/main.c @@ -434,6 +434,10 @@ unix_config (vlib_main_t * vm, unformat_input_t * input) vlib_default_runtime_dir, 0); } + error = setup_signal_handlers (um); + if (error) + return error; + if (um->pidfile) { if ((error = vlib_unix_validate_runtime_file (um, @@ -448,10 +452,6 @@ unix_config (vlib_main_t * vm, unformat_input_t * input) } } - error = setup_signal_handlers (um); - if (error) - return error; - if (!(um->flags & UNIX_FLAG_INTERACTIVE)) { openlog (vm->name, LOG_CONS | LOG_PERROR | LOG_PID, LOG_DAEMON); diff --git a/src/vnet/ipsec/ikev2.c b/src/vnet/ipsec/ikev2.c index 296654ec..a3dc7b87 100644 --- a/src/vnet/ipsec/ikev2.c +++ b/src/vnet/ipsec/ikev2.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1595,8 +1596,16 @@ ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, + sa->profile->lifetime; if (sa->profile->lifetime_jitter) { + // This is not much better than rand(3), which Coverity warns + // is unsuitable for security applications; random_u32 is + // however fast. If this perturbance to the expiration time + // needs to use a better RNG then we may need to use something + // like /dev/urandom which has significant overhead. + u32 rnd = (u32) (vlib_time_now (vnm->vlib_main) * 1e6); + rnd = random_u32 (&rnd); + child->time_to_expiration += - 1 + (rand () % sa->profile->lifetime_jitter); + 1 + (rnd % sa->profile->lifetime_jitter); } } diff --git a/src/vppinfra/socket.c b/src/vppinfra/socket.c index 7ade440c..37dcbbfd 100644 --- a/src/vppinfra/socket.c +++ b/src/vppinfra/socket.c @@ -359,9 +359,21 @@ clib_socket_init (clib_socket_t * s) && s->flags & SOCKET_ALLOW_GROUP_WRITE) { struct stat st = { 0 }; - stat (((struct sockaddr_un *) &addr)->sun_path, &st); + if (stat (((struct sockaddr_un *) &addr)->sun_path, &st) < 0) + { + error = clib_error_return_unix (0, "stat (fd %d, '%s')", + s->fd, s->config); + goto done; + } st.st_mode |= S_IWGRP; - chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode); + if (chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode) < + 0) + { + error = + clib_error_return_unix (0, "chmod (fd %d, '%s', mode %o)", + s->fd, s->config, st.st_mode); + goto done; + } } } else -- cgit 1.2.3-korg From 1948161b65aa89613f3b6d3714158048091a903c Mon Sep 17 00:00:00 2001 From: Dave Wallace Date: Fri, 15 Sep 2017 18:47:44 -0400 Subject: Add multi-vm Vagrantfile for vcl-test. - Existing Vagrantfile is symbolic link to the default Vagrantfile. - In order to run the multi-host vcl test, change Vagrantfile -> Vagrantfile.vcl_test - Fix socket_test.sh & vppcom bugs. Change-Id: I965b7f799135c86e989c08bf6c5909677ef38dea Signed-off-by: Dave Wallace --- extras/vagrant/Vagrantfile | 114 +----------------------------------- extras/vagrant/Vagrantfile.default | 111 +++++++++++++++++++++++++++++++++++ extras/vagrant/Vagrantfile.vcl_test | 110 ++++++++++++++++++++++++++++++++++ extras/vagrant/vcl_test.sh | 20 ++++--- src/uri/vppcom.c | 48 +++++++++------ test/scripts/socket_test.sh | 13 +++- 6 files changed, 272 insertions(+), 144 deletions(-) mode change 100644 => 120000 extras/vagrant/Vagrantfile create mode 100644 extras/vagrant/Vagrantfile.default create mode 100644 extras/vagrant/Vagrantfile.vcl_test (limited to 'src/uri/vppcom.c') diff --git a/extras/vagrant/Vagrantfile b/extras/vagrant/Vagrantfile deleted file mode 100644 index 07db660c..00000000 --- a/extras/vagrant/Vagrantfile +++ /dev/null @@ -1,113 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -Vagrant.configure(2) do |config| - - # Pick the right distro and bootstrap, default is ubuntu1604 - distro = ( ENV['VPP_VAGRANT_DISTRO'] || "ubuntu1604") - if distro == 'centos7' - config.vm.box = "puppetlabs/centos-7.2-64-nocm" - config.ssh.insert_key = false - else - config.vm.box = "puppetlabs/ubuntu-16.04-64-nocm" - end - config.vm.box_check_update = false - - config.vm.provision :shell, :path => File.join(File.dirname(__FILE__),"update.sh") - config.vm.provision :shell, :path => File.join(File.dirname(__FILE__),"build.sh"), :args => "/vpp vagrant" - - post_build = ( ENV['VPP_VAGRANT_POST_BUILD'] ) - if post_build == "test" - config.vm.provision "shell", inline: "echo Testing VPP; cd /vpp; make test" - elsif post_build == "install" - config.vm.provision :shell, :path => File.join(File.dirname(__FILE__),"install.sh"), :args => "/vpp" - config.vm.provision :shell, :path => File.join(File.dirname(__FILE__),"clearinterfaces.sh") - config.vm.provision :shell, :path => File.join(File.dirname(__FILE__),"run.sh") - elsif post_build == "vcl-test" - config.vm.provision :shell, :path => File.join(File.dirname(__FILE__),"vcl_test.sh"), :args => "/vpp vagrant" - end - - # Add .gnupg dir in so folks can sign patches - # Note, as gnupg puts socket files in that dir, we have - # to be cautious and make sure we are dealing with a plain file - homedir = File.expand_path("~/") - Dir["#{homedir}/.gnupg/**/*"].each do |fname| - if File.file?(fname) - destname = fname.sub(Regexp.escape("#{homedir}/"),'') - config.vm.provision "file", source: fname, destination: destname - end - end - - # Copy in the .gitconfig if it exists - if File.file?(File.expand_path("~/.gitconfig")) - config.vm.provision "file", source: "~/.gitconfig", destination: ".gitconfig" - end - - # vagrant-cachier caches apt/yum etc to speed subsequent - # vagrant up - # to enable, run - # vagrant plugin install vagrant-cachier - # - if Vagrant.has_plugin?("vagrant-cachier") - config.cache.scope = :box - end - - # Define some physical ports for your VMs to be used by DPDK - nics = (ENV['VPP_VAGRANT_NICS'] || "2").to_i(10) - for i in 1..nics - config.vm.network "private_network", type: "dhcp" - end - - # use http proxy if avaiable - if ENV['http_proxy'] && Vagrant.has_plugin?("vagrant-proxyconf") - config.proxy.http = ENV['http_proxy'] - config.proxy.https = ENV['https_proxy'] - config.proxy.no_proxy = "localhost,127.0.0.1" - end - - vmcpu=(ENV['VPP_VAGRANT_VMCPU'] || 2) - vmram=(ENV['VPP_VAGRANT_VMRAM'] || 4096) - - config.ssh.forward_agent = true - config.ssh.forward_x11 = true - - config.vm.provider "virtualbox" do |vb| - vb.customize ["modifyvm", :id, "--ioapic", "on"] - vb.memory = "#{vmram}" - vb.cpus = "#{vmcpu}" - - # rsync the vpp directory if provision hasn't happened yet - unless File.exist? (".vagrant/machines/default/virtualbox/action_provision") - config.vm.synced_folder "../../", "/vpp", type: "rsync", - rsync__auto: false, - rsync__exclude: [ - "build-root/build*/", - "build-root/install*/", - "build-root/images*/", - "build-root/*.deb", - "build-root/*.rpm", - "build-root/*.changes", - "build-root/python", - "build-root/deb/debian/*.dkms", - "build-root/deb/debian/*.install", - "build-root/deb/debian/changes", - "build-root/tools"] - end - - #support for the SSE4.x instruction is required in some versions of VB. - vb.customize ["setextradata", :id, "VBoxInternal/CPUM/SSE4.1", "1"] - vb.customize ["setextradata", :id, "VBoxInternal/CPUM/SSE4.2", "1"] - end - config.vm.provider "vmware_fusion" do |fusion,override| - fusion.vmx["memsize"] = "#{vmram}" - fusion.vmx["numvcpus"] = "#{vmcpu}" - end - config.vm.provider "libvirt" do |lv| - lv.memory = "#{vmram}" - lv.cpus = "#{vmcpu}" - end - config.vm.provider "vmware_workstation" do |vws,override| - vws.vmx["memsize"] = "#{vmram}" - vws.vmx["numvcpus"] = "#{vmcpu}" - end -end diff --git a/extras/vagrant/Vagrantfile b/extras/vagrant/Vagrantfile new file mode 120000 index 00000000..a0bc2252 --- /dev/null +++ b/extras/vagrant/Vagrantfile @@ -0,0 +1 @@ +Vagrantfile.default \ No newline at end of file diff --git a/extras/vagrant/Vagrantfile.default b/extras/vagrant/Vagrantfile.default new file mode 100644 index 00000000..8d6d02a6 --- /dev/null +++ b/extras/vagrant/Vagrantfile.default @@ -0,0 +1,111 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure(2) do |config| + + # Pick the right distro and bootstrap, default is ubuntu1604 + distro = ( ENV['VPP_VAGRANT_DISTRO'] || "ubuntu1604") + if distro == 'centos7' + config.vm.box = "puppetlabs/centos-7.2-64-nocm" + config.ssh.insert_key = false + else + config.vm.box = "puppetlabs/ubuntu-16.04-64-nocm" + end + config.vm.box_check_update = false + + config.vm.provision :shell, :path => File.join(File.dirname(__FILE__),"update.sh") + config.vm.provision :shell, :path => File.join(File.dirname(__FILE__),"build.sh"), :args => "/vpp vagrant" + + post_build = ( ENV['VPP_VAGRANT_POST_BUILD'] ) + if post_build == "test" + config.vm.provision "shell", inline: "echo Testing VPP; cd /vpp; make test" + elsif post_build == "install" + config.vm.provision :shell, :path => File.join(File.dirname(__FILE__),"install.sh"), :args => "/vpp" + config.vm.provision :shell, :path => File.join(File.dirname(__FILE__),"clearinterfaces.sh") + config.vm.provision :shell, :path => File.join(File.dirname(__FILE__),"run.sh") + end + + # Add .gnupg dir in so folks can sign patches + # Note, as gnupg puts socket files in that dir, we have + # to be cautious and make sure we are dealing with a plain file + homedir = File.expand_path("~/") + Dir["#{homedir}/.gnupg/**/*"].each do |fname| + if File.file?(fname) + destname = fname.sub(Regexp.escape("#{homedir}/"),'') + config.vm.provision "file", source: fname, destination: destname + end + end + + # Copy in the .gitconfig if it exists + if File.file?(File.expand_path("~/.gitconfig")) + config.vm.provision "file", source: "~/.gitconfig", destination: ".gitconfig" + end + + # vagrant-cachier caches apt/yum etc to speed subsequent + # vagrant up + # to enable, run + # vagrant plugin install vagrant-cachier + # + if Vagrant.has_plugin?("vagrant-cachier") + config.cache.scope = :box + end + + # Define some physical ports for your VMs to be used by DPDK + nics = (ENV['VPP_VAGRANT_NICS'] || "2").to_i(10) + for i in 1..nics + config.vm.network "private_network", type: "dhcp" + end + + # use http proxy if avaiable + if ENV['http_proxy'] && Vagrant.has_plugin?("vagrant-proxyconf") + config.proxy.http = ENV['http_proxy'] + config.proxy.https = ENV['https_proxy'] + config.proxy.no_proxy = "localhost,127.0.0.1" + end + + vmcpu=(ENV['VPP_VAGRANT_VMCPU'] || 2) + vmram=(ENV['VPP_VAGRANT_VMRAM'] || 4096) + + config.ssh.forward_agent = true + config.ssh.forward_x11 = true + + config.vm.provider "virtualbox" do |vb| + vb.customize ["modifyvm", :id, "--ioapic", "on"] + vb.memory = "#{vmram}" + vb.cpus = "#{vmcpu}" + + # rsync the vpp directory if provision hasn't happened yet + unless File.exist? (".vagrant/machines/default/virtualbox/action_provision") + config.vm.synced_folder "../../", "/vpp", type: "rsync", + rsync__auto: false, + rsync__exclude: [ + "build-root/build*/", + "build-root/install*/", + "build-root/images*/", + "build-root/*.deb", + "build-root/*.rpm", + "build-root/*.changes", + "build-root/python", + "build-root/deb/debian/*.dkms", + "build-root/deb/debian/*.install", + "build-root/deb/debian/changes", + "build-root/tools"] + end + + #support for the SSE4.x instruction is required in some versions of VB. + vb.customize ["setextradata", :id, "VBoxInternal/CPUM/SSE4.1", "1"] + vb.customize ["setextradata", :id, "VBoxInternal/CPUM/SSE4.2", "1"] + end + config.vm.provider "vmware_fusion" do |fusion,override| + fusion.vmx["memsize"] = "#{vmram}" + fusion.vmx["numvcpus"] = "#{vmcpu}" + end + config.vm.provider "libvirt" do |lv| + lv.memory = "#{vmram}" + lv.cpus = "#{vmcpu}" + end + config.vm.provider "vmware_workstation" do |vws,override| + vws.vmx["memsize"] = "#{vmram}" + vws.vmx["numvcpus"] = "#{vmcpu}" + end +end diff --git a/extras/vagrant/Vagrantfile.vcl_test b/extras/vagrant/Vagrantfile.vcl_test new file mode 100644 index 00000000..92d6832a --- /dev/null +++ b/extras/vagrant/Vagrantfile.vcl_test @@ -0,0 +1,110 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure(2) do |config| + + # Pick the right distro and bootstrap, default is ubuntu1604 + distro = ( ENV['VPP_VAGRANT_DISTRO'] || "ubuntu1604") + if distro == 'centos7' + config.vm.box = "puppetlabs/centos-7.2-64-nocm" + config.ssh.insert_key = false + else + config.vm.box = "puppetlabs/ubuntu-16.04-64-nocm" + end + config.vm.box_check_update = false + + config.vm.provision :shell, :path => File.join(File.dirname(__FILE__),"update.sh") + config.vm.provision :shell, :path => File.join(File.dirname(__FILE__),"build.sh"), :args => "/vpp vagrant" + + # Create VCL client and server VM's + config.vm.define "vcl-server" do |server| + server.vm.provision :shell, :path => File.join(File.dirname(__FILE__),"vcl_test.sh"), :args => "/vpp vagrant vcl-server" + end + config.vm.define "vcl-client" do |client| + client.vm.provision :shell, :path => File.join(File.dirname(__FILE__),"vcl_test.sh"), :args => "/vpp vagrant vcl-client" + end + + # Add .gnupg dir in so folks can sign patches + # Note, as gnupg puts socket files in that dir, we have + # to be cautious and make sure we are dealing with a plain file + homedir = File.expand_path("~/") + Dir["#{homedir}/.gnupg/**/*"].each do |fname| + if File.file?(fname) + destname = fname.sub(Regexp.escape("#{homedir}/"),'') + config.vm.provision "file", source: fname, destination: destname + end + end + + # Copy in the .gitconfig if it exists + if File.file?(File.expand_path("~/.gitconfig")) + config.vm.provision "file", source: "~/.gitconfig", destination: ".gitconfig" + end + + # vagrant-cachier caches apt/yum etc to speed subsequent + # vagrant up + # to enable, run + # vagrant plugin install vagrant-cachier + # + if Vagrant.has_plugin?("vagrant-cachier") + config.cache.scope = :box + end + + # Define some physical ports for your VMs to be used by DPDK + nics = (ENV['VPP_VAGRANT_NICS'] || "2").to_i(10) + for i in 1..nics + config.vm.network "private_network", type: "dhcp" + end + + # use http proxy if avaiable + if ENV['http_proxy'] && Vagrant.has_plugin?("vagrant-proxyconf") + config.proxy.http = ENV['http_proxy'] + config.proxy.https = ENV['https_proxy'] + config.proxy.no_proxy = "localhost,127.0.0.1" + end + + vmcpu=(ENV['VPP_VAGRANT_VMCPU'] || 2) + vmram=(ENV['VPP_VAGRANT_VMRAM'] || 4096) + + config.ssh.forward_agent = true + config.ssh.forward_x11 = true + + config.vm.provider "virtualbox" do |vb| + vb.customize ["modifyvm", :id, "--ioapic", "on"] + vb.memory = "#{vmram}" + vb.cpus = "#{vmcpu}" + + # rsync the vpp directory if provision hasn't happened yet + unless File.exist? (".vagrant/machines/client/virtualbox/action_provision") + config.vm.synced_folder "../../", "/vpp", type: "rsync", + rsync__auto: false, + rsync__exclude: [ + "build-root/build*/", + "build-root/install*/", + "build-root/images*/", + "build-root/*.deb", + "build-root/*.rpm", + "build-root/*.changes", + "build-root/python", + "build-root/deb/debian/*.dkms", + "build-root/deb/debian/*.install", + "build-root/deb/debian/changes", + "build-root/tools"] + end + + #support for the SSE4.x instruction is required in some versions of VB. + vb.customize ["setextradata", :id, "VBoxInternal/CPUM/SSE4.1", "1"] + vb.customize ["setextradata", :id, "VBoxInternal/CPUM/SSE4.2", "1"] + end + config.vm.provider "vmware_fusion" do |fusion,override| + fusion.vmx["memsize"] = "#{vmram}" + fusion.vmx["numvcpus"] = "#{vmcpu}" + end + config.vm.provider "libvirt" do |lv| + lv.memory = "#{vmram}" + lv.cpus = "#{vmcpu}" + end + config.vm.provider "vmware_workstation" do |vws,override| + vws.vmx["memsize"] = "#{vmram}" + vws.vmx["numvcpus"] = "#{vmcpu}" + end +end diff --git a/extras/vagrant/vcl_test.sh b/extras/vagrant/vcl_test.sh index 9fb924ae..3be18517 100644 --- a/extras/vagrant/vcl_test.sh +++ b/extras/vagrant/vcl_test.sh @@ -1,23 +1,25 @@ #!/bin/bash -# Get Command Line arguements if present -VPP_DIR=$1 -if [ "x$1" != "x" ]; then +if [ -n "$1" ]; then VPP_DIR=$1 else VPP_DIR=`dirname $0`/../../ fi -if [ "x$2" != "x" ]; then +if [ -n "$2" ]; then SUDOCMD="sudo -H -u $2" fi echo 'Building VCL test apps' cd $VPP_DIR $SUDOCMD perl -pi -e 's/noinst_PROGRAMS/bin_PROGRAMS/g' $VPP_DIR/src/uri.am -$SUDOCMD make build-release -echo "export WS_ROOT=$VPP_DIR" | sudo -H -u vagrant tee /home/vagrant/.bash_aliases -source /home/vagrant/.bash_aliases -sudo cp $VPP_DIR/src/vpp/conf/80-vpp.conf /etc/sysctl.d -sudo sysctl -p/etc/sysctl.d/80-vpp.conf +$SUDOCMD make dpdk-install-dev build-release +sudo sysctl -p$VPP_DIR/src/vpp/conf/80-vpp.conf sudo modprobe uio_pci_generic + +if [ "$2" = "vagrant" ] && [ -d "/home/vagrant" ] ; then + dot_bash_aliases="/home/$2/.bash_aliases" + echo "export WS_ROOT=$VPP_DIR" | $SUDOCMD tee $dot_bash_aliases + source $dot_bash_aliases +fi + diff --git a/src/uri/vppcom.c b/src/uri/vppcom.c index aa307f1d..8a8a806c 100644 --- a/src/uri/vppcom.c +++ b/src/uri/vppcom.c @@ -852,19 +852,15 @@ vl_api_unbind_sock_reply_t_handler (vl_api_unbind_sock_reply_t * mp) clib_spinlock_lock (&vcm->sessions_lockp); rv = vppcom_session_at_index (vcm->bind_session_index, &session); - if (PREDICT_FALSE (rv)) + if (rv == VPPCOM_OK) { - if (VPPCOM_DEBUG > 1) - clib_warning ("[%d] invalid session, sid (%d) has been closed!", - vcm->my_pid, vcm->bind_session_index); - } + if ((VPPCOM_DEBUG > 1) && (mp->retval)) + clib_warning ("[%d] unbind failed: %U", vcm->my_pid, format_api_error, + ntohl (mp->retval)); - if (mp->retval) - clib_warning ("[%d] unbind failed: %U", vcm->my_pid, format_api_error, - ntohl (mp->retval)); - - vcm->bind_session_index = ~0; - session->state = STATE_START; + vcm->bind_session_index = ~0; + session->state = STATE_START; + } clib_spinlock_unlock (&vcm->sessions_lockp); } @@ -993,6 +989,7 @@ vl_api_accept_session_t_handler (vl_api_accept_session_t * mp) unix_shared_memory_queue_t *); session->state = STATE_ACCEPT; session->is_cut_thru = 0; + session->is_server = 1; session->port = ntohs (mp->port); session->is_ip4 = mp->is_ip4; clib_memcpy (session->ip, mp->ip, sizeof (session->ip)); @@ -1277,10 +1274,6 @@ vppcom_session_disconnect (u32 session_index) vcm->my_pid, vppcom_retval_str (rv), rv); return rv; } - - clib_spinlock_lock (&vcm->sessions_lockp); - pool_put_index (vcm->sessions, session_index); - clib_spinlock_unlock (&vcm->sessions_lockp); return VPPCOM_OK; } @@ -1853,14 +1846,31 @@ vppcom_session_close (uint32_t session_index) if (session->is_cut_thru) { if (session->is_server) - rv = vppcom_session_unbind_cut_thru (session); + { + rv = vppcom_session_unbind_cut_thru (session); + if ((VPPCOM_DEBUG > 0) && (rv < 0)) + clib_warning ("[%d] unbind cut-thru (session %d) failed, " + "rv = %s (%d)", + vcm->my_pid, session_index, + vppcom_retval_str (rv), rv); + } + } + else if (session->is_server) + { + rv = vppcom_session_unbind (session_index); + if ((VPPCOM_DEBUG > 0) && (rv < 0)) + clib_warning ("[%d] unbind (session %d) failed, rv = %s (%d)", + vcm->my_pid, session_index, vppcom_retval_str (rv), rv); } else { - rv = (session->is_server) ? - vppcom_session_unbind (session_index) : - vppcom_session_disconnect (session_index); + rv = vppcom_session_disconnect (session_index); + if ((VPPCOM_DEBUG > 0) && (rv < 0)) + clib_warning ("[%d] disconnect (session %d) failed, rv = %s (%d)", + vcm->my_pid, session_index, vppcom_retval_str (rv), rv); } + if (rv < 0) + return rv; clib_spinlock_lock (&vcm->sessions_lockp); pool_put_index (vcm->sessions, session_index); diff --git a/test/scripts/socket_test.sh b/test/scripts/socket_test.sh index 8c3f20a2..1573b48a 100755 --- a/test/scripts/socket_test.sh +++ b/test/scripts/socket_test.sh @@ -9,7 +9,7 @@ vpp_shm_dir="/dev/shm/" vpp_run_dir="/run/vpp" lib64_dir="$WS_ROOT/build-root/install-vpp-native/vpp/lib64/" lib64_debug_dir="$WS_ROOT/build-root/install-vpp_debug-native/vpp/lib64/" -dpdk_devbind="$WS_ROOT/build-root/install-vpp-native/dpdk/share/dpdk/usertools/dpdk-devbind.py" +dpdk_devbind="/usr/share/dpdk/usertools/dpdk-devbind.py" docker_vpp_dir="/vpp/" docker_app_dir="/vpp/" docker_lib64_dir="/vpp-lib64/" @@ -302,6 +302,13 @@ if [[ $run_test =~ .*"_vcl" ]] && [ $iperf3 -eq 1 ] ; then env_test_failed="true" fi +if [ -n "$mult_host"] && [ ! -f "$dpdk_devbind" ] ; then + echo "ERROR: Can't find dpdk-devbind.py!" + echo " Run \"cd \$WS_ROOT; make dpdk-install-dev\" to install it." + echo + env_test_failed="true" +fi + if [ -n "$env_test_failed" ] ; then exit 1 fi @@ -458,8 +465,8 @@ write_script_header() { echo "$bash_header" > $1 echo -e "#\n# $1 generated on $(date)\n#" >> $1 if [ $leave_tmp_files -eq 0 ] ; then - if [ -n "$multi_host" ] ; then - echo "trap \"rm -f $1 $2 $tmp_vpp_exec_file; sudo $dpdk_devbind -e $vpp_eth_kernel_driver $vpp_eth_pci_id; sudo ifup $vpp_eth_name\" $trap_signals" >> $1 + if [ -n "$multi_host" ] && [[ "$3" == VPP* ]] ; then + echo "trap \"rm -f $1 $2 $tmp_vpp_exec_file; sudo $dpdk_devbind -b $vpp_eth_kernel_driver $vpp_eth_pci_id; sudo ifup $vpp_eth_name\" $trap_signals" >> $1 else echo "trap \"rm -f $1 $2 $tmp_vpp_exec_file\" $trap_signals" >> $1 fi -- cgit 1.2.3-korg From b2bcad6238b7e8a669ae29c74079eb9bb9fbb694 Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Mon, 18 Sep 2017 08:51:22 -0400 Subject: Fixes for issues Coverity has reported (VPP-972) 177117: fstat() returns -1 on error; the code is checking for any positive value instead 175142: final return could never be reached; simple refactoring 175235,175236: Warning suppressed with an explicit cast to (void) 174817: Final return couldn't be reached; is is_in_order is 0 then 'rv' is already returned above 172095,172093: If is_is_set does not get set to 1, then return 0 has already been invoked 174405: Re-kill this (nothing sets rv) 171136: Looks like a cmd line flag to set test_bytes was missing; added it, and refactored the argc/argv processing to avoid two other potential segv's 176813: Add range checking for term width/height. First stab at a reasonable range is 1-512 for both. 175350: Fix implicit casting in shift operation 174272: Not a c+p error; try using a coverity annotation to ignore it 174273,175320: Annotated FORWARD_NULL Change-Id: I58d0f860fc2209f59f8d1b6b344d631b8d429ace Signed-off-by: Chris Luke --- src/uri/sock_test_client.c | 1 + src/uri/uri_socket_test.c | 24 ++++++++++++++++++++++-- src/uri/vppcom.c | 8 ++++++-- src/vlib/linux/physmem.c | 2 +- src/vlib/unix/cli.c | 30 ++++++++++++++++++++++++++++++ src/vnet/mpls/mpls_api.c | 2 +- src/vnet/session/session.c | 5 +---- src/vnet/session/session_cli.c | 37 +++++++------------------------------ src/vnet/session/session_lookup.c | 8 ++++---- src/vppinfra/linux/mem.c | 2 +- 10 files changed, 74 insertions(+), 45 deletions(-) (limited to 'src/uri/vppcom.c') diff --git a/src/uri/sock_test_client.c b/src/uri/sock_test_client.c index ab8e5a0e..151c90b2 100644 --- a/src/uri/sock_test_client.c +++ b/src/uri/sock_test_client.c @@ -429,6 +429,7 @@ exit_client (void) tsock = &scm->test_socket[i]; tsock->cfg.test = SOCK_TEST_TYPE_EXIT; + /* coverity[COPY_PASTE_ERROR] */ if (ctrl->cfg.verbose) { printf ("\nCLIENT (fd %d): Sending exit cfg to server...\n", diff --git a/src/uri/uri_socket_test.c b/src/uri/uri_socket_test.c index 5f7084d5..4469b03d 100644 --- a/src/uri/uri_socket_test.c +++ b/src/uri/uri_socket_test.c @@ -36,8 +36,6 @@ main (int argc, char *argv[]) if (argc >= 3) { - bytes = ((long) atoi (argv[4])) << 20; - no_echo = atoi (argv[3]); portno = atoi (argv[2]); server = gethostbyname (argv[1]); if (server == NULL) @@ -45,6 +43,28 @@ main (int argc, char *argv[]) clib_unix_warning ("gethostbyname"); exit (1); } + + argc -= 3; + argv += 3; + + if (argc) + { + bytes = ((long) atoi (argv[0])) << 20; + argc--; + argv++; + } + if (argc) + { + no_echo = atoi (argv[0]); + argc--; + argv++; + } + if (argc) + { + test_bytes = atoi (argv[0]); + argc--; + argv++; + } } else { diff --git a/src/uri/vppcom.c b/src/uri/vppcom.c index 8a8a806c..c7ae0ea5 100644 --- a/src/uri/vppcom.c +++ b/src/uri/vppcom.c @@ -1478,7 +1478,7 @@ vppcom_cfg_read (char *conf_fname) while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - unformat_user (input, unformat_line_input, line_input); + (void) unformat_user (input, unformat_line_input, line_input); unformat_skip_white_space (line_input); if (unformat (line_input, "vppcom {")) @@ -2359,12 +2359,14 @@ vppcom_select (unsigned long n_bits, unsigned long *read_map, clib_bitmap_get (vcm->ex_bitmap, session_index) && (rv < 0)) { // TBD: clib_warning + /* coverity[FORWARD_NULL] */ clib_bitmap_set_no_check (except_map, session_index, 1); bits_set++; } else if (rv > 0) { // TBD: clib_warning + /* coverity[FORWARD_NULL] */ clib_bitmap_set_no_check (read_map, session_index, 1); bits_set++; } @@ -2387,9 +2389,10 @@ vppcom_select (unsigned long n_bits, unsigned long *read_map, rv = vppcom_session_write_ready (session, session_index); clib_spinlock_unlock (&vcm->sessions_lockp); - if (rv > 0) + if (rv > 0 ) { // TBD: clib_warning + /* coverity[FORWARD_NULL] */ clib_bitmap_set_no_check (write_map, session_index, 1); bits_set++; } @@ -2415,6 +2418,7 @@ vppcom_select (unsigned long n_bits, unsigned long *read_map, if (rv < 0) { // TBD: clib_warning + /* coverity[FORWARD_NULL] */ clib_bitmap_set_no_check (except_map, session_index, 1); bits_set++; } diff --git a/src/vlib/linux/physmem.c b/src/vlib/linux/physmem.c index 3cc42a06..6d3f7c55 100644 --- a/src/vlib/linux/physmem.c +++ b/src/vlib/linux/physmem.c @@ -157,7 +157,7 @@ unix_physmem_region_alloc (vlib_main_t * vm, char *name, u32 size, pr->mem = alloc.addr; pr->log2_page_size = alloc.log2_page_size; pr->n_pages = alloc.n_pages; - pr->size = pr->n_pages << pr->log2_page_size; + pr->size = (u64) pr->n_pages << (u64) pr->log2_page_size; pr->page_mask = (1 << pr->log2_page_size) - 1; pr->numa_node = numa_node; pr->name = format (0, "%s", name); diff --git a/src/vlib/unix/cli.c b/src/vlib/unix/cli.c index 1567cc2a..1624ce38 100644 --- a/src/vlib/unix/cli.c +++ b/src/vlib/unix/cli.c @@ -91,6 +91,15 @@ * protocol message. This is a saftey measure. */ #define UNIX_CLI_MAX_DEPTH_TELNET 24 +/** Minimum terminal width we will accept */ +#define UNIX_CLI_MIN_TERMINAL_WIDTH 1 +/** Maximum terminal width we will accept */ +#define UNIX_CLI_MAX_TERMINAL_WIDTH 512 +/** Minimum terminal height we will accept */ +#define UNIX_CLI_MIN_TERMINAL_HEIGHT 1 +/** Maximum terminal height we will accept */ +#define UNIX_CLI_MAX_TERMINAL_HEIGHT 512 + /** Unix standard in */ #define UNIX_CLI_STDIN_FD 0 @@ -1164,10 +1173,21 @@ unix_cli_process_telnet (unix_main_t * um, /* Window size */ if (i != 8) /* check message is correct size */ break; + cf->width = clib_net_to_host_u16 (*((u16 *) (input_vector + 3))); + if (cf->width > UNIX_CLI_MAX_TERMINAL_WIDTH) + cf->width = UNIX_CLI_MAX_TERMINAL_WIDTH; + if (cf->width < UNIX_CLI_MIN_TERMINAL_WIDTH) + cf->width = UNIX_CLI_MIN_TERMINAL_WIDTH; + cf->height = clib_net_to_host_u16 (*((u16 *) (input_vector + 5))); + if (cf->height > UNIX_CLI_MAX_TERMINAL_HEIGHT) + cf->height = UNIX_CLI_MAX_TERMINAL_HEIGHT; + if (cf->height < UNIX_CLI_MIN_TERMINAL_HEIGHT) + cf->height = UNIX_CLI_MIN_TERMINAL_HEIGHT; + /* reindex pager buffer */ unix_cli_pager_reindex (cf); /* redraw page */ @@ -2539,8 +2559,18 @@ unix_cli_resize_interrupt (int signum) /* We can't trust ws.XXX... */ return; } + cf->width = ws.ws_col; + if (cf->width > UNIX_CLI_MAX_TERMINAL_WIDTH) + cf->width = UNIX_CLI_MAX_TERMINAL_WIDTH; + if (cf->width < UNIX_CLI_MIN_TERMINAL_WIDTH) + cf->width = UNIX_CLI_MIN_TERMINAL_WIDTH; + cf->height = ws.ws_row; + if (cf->height > UNIX_CLI_MAX_TERMINAL_HEIGHT) + cf->height = UNIX_CLI_MAX_TERMINAL_HEIGHT; + if (cf->height < UNIX_CLI_MIN_TERMINAL_HEIGHT) + cf->height = UNIX_CLI_MIN_TERMINAL_HEIGHT; /* Reindex the pager buffer */ unix_cli_pager_reindex (cf); diff --git a/src/vnet/mpls/mpls_api.c b/src/vnet/mpls/mpls_api.c index 988c2c98..762c40ff 100644 --- a/src/vnet/mpls/mpls_api.c +++ b/src/vnet/mpls/mpls_api.c @@ -96,7 +96,7 @@ vl_api_mpls_table_add_del_t_handler (vl_api_mpls_table_add_del_t * mp) else mpls_table_delete (ntohl (mp->mt_table_id), 1); - rv = (rv == 0) ? vnm->api_errno : rv; + // NB: Nothing sets rv; none of the above returns an error REPLY_MACRO (VL_API_MPLS_TABLE_ADD_DEL_REPLY); } diff --git a/src/vnet/session/session.c b/src/vnet/session/session.c index 4544f9a0..792e6612 100644 --- a/src/vnet/session/session.c +++ b/src/vnet/session/session.c @@ -267,10 +267,7 @@ stream_session_enqueue_data (transport_connection_t * tc, vlib_buffer_t * b, } } - if (is_in_order) - return enqueued; - - return 0; + return enqueued; } /** Check if we have space in rx fifo to push more bytes */ diff --git a/src/vnet/session/session_cli.c b/src/vnet/session/session_cli.c index d9f516be..8c30a1df 100755 --- a/src/vnet/session/session_cli.c +++ b/src/vnet/session/session_cli.c @@ -127,13 +127,8 @@ unformat_stream_session_id (unformat_input_t * input, va_list * args) *is_ip4 = 0; tuple_is_set = 1; } - else - return 0; - - if (tuple_is_set) - return 1; - return 0; + return tuple_is_set; } uword @@ -144,21 +139,12 @@ unformat_stream_session (unformat_input_t * input, va_list * args) u8 proto = ~0; ip46_address_t lcl, rmt; u32 lcl_port = 0, rmt_port = 0; - u8 is_ip4 = 0, s_type = ~0, id_is_set = 0; + u8 is_ip4 = 0, s_type = ~0; - if (unformat (input, "%U", unformat_stream_session_id, &proto, &lcl, &rmt, - &lcl_port, &rmt_port, &is_ip4)) - { - id_is_set = 1; - } - else + if (!unformat (input, "%U", unformat_stream_session_id, &proto, &lcl, &rmt, + &lcl_port, &rmt_port, &is_ip4)) return 0; - if (!id_is_set) - { - return 0; - } - s_type = session_type_from_proto_and_ip (proto, is_ip4); if (is_ip4) s = stream_session_lookup4 (&lcl.ip4, &rmt.ip4, @@ -185,21 +171,12 @@ unformat_transport_connection (unformat_input_t * input, va_list * args) u8 proto = ~0; ip46_address_t lcl, rmt; u32 lcl_port = 0, rmt_port = 0; - u8 is_ip4 = 0, s_type = ~0, id_is_set = 0; + u8 is_ip4 = 0, s_type = ~0; - if (unformat (input, "%U", unformat_stream_session_id, &proto, &lcl, &rmt, - &lcl_port, &rmt_port, &is_ip4)) - { - id_is_set = 1; - } - else + if (!unformat (input, "%U", unformat_stream_session_id, &proto, &lcl, &rmt, + &lcl_port, &rmt_port, &is_ip4)) return 0; - if (!id_is_set) - { - return 0; - } - proto = (proto == (u8) ~ 0) ? suggested_proto : proto; if (proto == (u8) ~ 0) return 0; diff --git a/src/vnet/session/session_lookup.c b/src/vnet/session/session_lookup.c index 0f9abf9a..4487b1c3 100644 --- a/src/vnet/session/session_lookup.c +++ b/src/vnet/session/session_lookup.c @@ -233,15 +233,15 @@ stream_session_half_open_table_add (transport_connection_t * tc, u64 value) { make_v4_ss_kv_from_tc (&kv4, tc); kv4.value = value; - clib_bihash_add_del_16_8 (&sl->v4_half_open_hash, &kv4, - 1 /* is_add */ ); + (void) clib_bihash_add_del_16_8 (&sl->v4_half_open_hash, &kv4, + 1 /* is_add */ ); } else { make_v6_ss_kv_from_tc (&kv6, tc); kv6.value = value; - clib_bihash_add_del_48_8 (&sl->v6_half_open_hash, &kv6, - 1 /* is_add */ ); + (void) clib_bihash_add_del_48_8 (&sl->v6_half_open_hash, &kv6, + 1 /* is_add */ ); } } diff --git a/src/vppinfra/linux/mem.c b/src/vppinfra/linux/mem.c index 665ddf61..df46763a 100644 --- a/src/vppinfra/linux/mem.c +++ b/src/vppinfra/linux/mem.c @@ -49,7 +49,7 @@ int clib_mem_vm_get_log2_page_size (int fd) { struct stat st = { 0 }; - if (fstat (fd, &st)) + if (fstat (fd, &st) == -1) return 0; return min_log2 (st.st_blksize); } -- cgit 1.2.3-korg