X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fsession%2Fsession_node.c;h=0ec158fb4292de8524affa5d7d5d168512559309;hb=HEAD;hp=c29e0590aa8ac97e4455060c237bf72687567742;hpb=20de85b6da7e0b6dd0d73bc8358e7c67564d0c36;p=vpp.git diff --git a/src/vnet/session/session_node.c b/src/vnet/session/session_node.c index c29e0590aa8..0ec158fb429 100644 --- a/src/vnet/session/session_node.c +++ b/src/vnet/session/session_node.c @@ -139,13 +139,17 @@ session_mq_listen_handler (session_worker_t *wrk, session_evt_elt_t *elt) a->sep_ext.ext_cfg = session_mq_get_ext_config (app, mp->ext_config); if ((rv = vnet_listen (a))) - clib_warning ("listen returned: %U", format_session_error, rv); + session_worker_stat_error_inc (wrk, rv, 1); app_wrk = application_get_worker (app, mp->wrk_index); - mq_send_session_bound_cb (app_wrk->wrk_index, mp->context, a->handle, rv); + app_worker_listened_notify (app_wrk, a->handle, mp->context, rv); if (mp->ext_config) session_mq_free_ext_config (app, mp->ext_config); + + /* Make sure events are flushed before releasing barrier, to avoid + * potential race with accept. */ + app_wrk_flush_wrk_events (app_wrk, 0); } static void @@ -170,7 +174,8 @@ session_mq_listen_uri_handler (session_worker_t *wrk, session_evt_elt_t *elt) rv = vnet_bind_uri (a); app_wrk = application_get_worker (app, 0); - mq_send_session_bound_cb (app_wrk->wrk_index, mp->context, a->handle, rv); + app_worker_listened_notify (app_wrk, a->handle, mp->context, rv); + app_wrk_flush_wrk_events (app_wrk, 0); } static void @@ -178,6 +183,7 @@ session_mq_connect_one (session_connect_msg_t *mp) { vnet_connect_args_t _a, *a = &_a; app_worker_t *app_wrk; + session_worker_t *wrk; application_t *app; int rv; @@ -211,9 +217,10 @@ session_mq_connect_one (session_connect_msg_t *mp) if ((rv = vnet_connect (a))) { - clib_warning ("connect returned: %U", format_session_error, rv); + wrk = session_main_get_worker (vlib_get_thread_index ()); + session_worker_stat_error_inc (wrk, rv, 1); app_wrk = application_get_worker (app, mp->wrk_index); - mq_send_session_connected_cb (app_wrk->wrk_index, mp->context, 0, rv); + app_worker_connect_notify (app_wrk, 0, rv, mp->context); } if (mp->ext_config) @@ -224,23 +231,20 @@ static void session_mq_handle_connects_rpc (void *arg) { u32 max_connects = 32, n_connects = 0; - vlib_main_t *vm = vlib_get_main (); session_evt_elt_t *he, *elt, *next; - session_worker_t *fwrk, *wrk; + session_worker_t *fwrk; - ASSERT (vlib_get_thread_index () == 0); + ASSERT (session_vlib_thread_is_cl_thread ()); /* Pending connects on linked list pertaining to first worker */ - fwrk = session_main_get_worker (1); + fwrk = session_main_get_worker (transport_cl_thread ()); if (!fwrk->n_pending_connects) - goto update_state; - - vlib_worker_thread_barrier_sync (vm); + return; he = clib_llist_elt (fwrk->event_elts, fwrk->pending_connects); elt = clib_llist_next (fwrk->event_elts, evt_list, he); - /* Avoid holding the barrier for too long */ + /* Avoid holding the worker for too long */ while (n_connects < max_connects && elt != he) { next = clib_llist_next (fwrk->event_elts, evt_list, elt); @@ -254,45 +258,10 @@ session_mq_handle_connects_rpc (void *arg) /* Decrement with worker barrier */ fwrk->n_pending_connects -= n_connects; - - vlib_worker_thread_barrier_release (vm); - -update_state: - - /* Switch worker to poll mode if it was in interrupt mode and had work or - * back to interrupt if threshold of loops without a connect is passed. - * While in poll mode, reprogram connects rpc */ - wrk = session_main_get_worker (0); - if (wrk->state != SESSION_WRK_POLLING) - { - if (n_connects) - { - session_wrk_set_state (wrk, SESSION_WRK_POLLING); - vlib_node_set_state (vm, session_queue_node.index, - VLIB_NODE_STATE_POLLING); - wrk->no_connect_loops = 0; - } - } - else + if (fwrk->n_pending_connects > 0) { - if (!n_connects) - { - if (++wrk->no_connect_loops > 1e5) - { - session_wrk_set_state (wrk, SESSION_WRK_INTERRUPT); - vlib_node_set_state (vm, session_queue_node.index, - VLIB_NODE_STATE_INTERRUPT); - } - } - else - wrk->no_connect_loops = 0; - } - - if (wrk->state == SESSION_WRK_POLLING) - { - elt = session_evt_alloc_ctrl (wrk); - elt->evt.event_type = SESSION_CTRL_EVT_RPC; - elt->evt.rpc_args.fp = session_mq_handle_connects_rpc; + session_send_rpc_evt_to_thread_force (fwrk->vm->thread_index, + session_mq_handle_connects_rpc, 0); } } @@ -302,20 +271,28 @@ session_mq_connect_handler (session_worker_t *wrk, session_evt_elt_t *elt) u32 thread_index = wrk - session_main.wrk; session_evt_elt_t *he; - /* No workers, so just deal with the connect now */ - if (PREDICT_FALSE (!thread_index)) + if (PREDICT_FALSE (thread_index > transport_cl_thread ())) { - session_mq_connect_one (session_evt_ctrl_data (wrk, elt)); + clib_warning ("Connect on wrong thread. Dropping"); return; } - if (PREDICT_FALSE (thread_index != 1)) + /* If on worker, check if main has any pending messages. Avoids reordering + * with other control messages that need to be handled by main + */ + if (thread_index) { - clib_warning ("Connect on wrong thread. Dropping"); - return; + he = clib_llist_elt (wrk->event_elts, wrk->evts_pending_main); + + /* Events pending on main, postpone to avoid reordering */ + if (!clib_llist_is_empty (wrk->event_elts, evt_list, he)) + { + clib_llist_add_tail (wrk->event_elts, evt_list, elt, he); + return; + } } - /* Add to pending list to be handled by main thread */ + /* Add to pending list to be handled by first worker */ he = clib_llist_elt (wrk->event_elts, wrk->pending_connects); clib_llist_add_tail (wrk->event_elts, evt_list, elt, he); @@ -323,9 +300,8 @@ session_mq_connect_handler (session_worker_t *wrk, session_evt_elt_t *elt) wrk->n_pending_connects += 1; if (wrk->n_pending_connects == 1) { - vlib_node_set_interrupt_pending (vlib_get_main_by_index (0), - session_queue_node.index); - session_send_rpc_evt_to_thread (0, session_mq_handle_connects_rpc, 0); + session_send_rpc_evt_to_thread_force (thread_index, + session_mq_handle_connects_rpc, 0); } } @@ -351,9 +327,9 @@ session_mq_connect_uri_handler (session_worker_t *wrk, session_evt_elt_t *elt) a->app_index = app->app_index; if ((rv = vnet_connect_uri (a))) { - clib_warning ("connect_uri returned: %d", rv); + session_worker_stat_error_inc (wrk, rv, 1); app_wrk = application_get_worker (app, 0 /* default wrk only */ ); - mq_send_session_connected_cb (app_wrk->wrk_index, mp->context, 0, rv); + app_worker_connect_notify (app_wrk, 0, rv, mp->context); } } @@ -433,13 +409,13 @@ session_mq_unlisten_handler (session_worker_t *wrk, session_evt_elt_t *elt) a->wrk_map_index = mp->wrk_index; if ((rv = vnet_unlisten (a))) - clib_warning ("unlisten returned: %d", rv); + session_worker_stat_error_inc (wrk, rv, 1); app_wrk = application_get_worker (app, a->wrk_map_index); if (!app_wrk) return; - mq_send_unlisten_reply (app_wrk, sh, mp->context, rv); + app_worker_unlisten_reply (app_wrk, sh, mp->context, rv); } static void @@ -480,28 +456,29 @@ session_mq_accepted_reply_handler (session_worker_t *wrk, a->app_index = mp->context; a->handle = mp->handle; vnet_disconnect_session (a); + s->app_wrk_index = SESSION_INVALID_INDEX; return; } /* Special handling for cut-through sessions */ if (!session_has_transport (s)) { - s->session_state = SESSION_STATE_READY; + session_set_state (s, SESSION_STATE_READY); ct_session_connect_notify (s, SESSION_E_NONE); return; } old_state = s->session_state; - s->session_state = SESSION_STATE_READY; + session_set_state (s, SESSION_STATE_READY); if (!svm_fifo_is_empty_prod (s->rx_fifo)) - app_worker_lock_and_send_event (app_wrk, s, SESSION_IO_EVT_RX); + app_worker_rx_notify (app_wrk, s); /* Closed while waiting for app to reply. Resend disconnect */ if (old_state >= SESSION_STATE_TRANSPORT_CLOSING) { app_worker_close_notify (app_wrk, s); - s->session_state = old_state; + session_set_state (s, old_state); return; } } @@ -514,15 +491,13 @@ session_mq_reset_reply_handler (void *data) app_worker_t *app_wrk; session_t *s; application_t *app; - u32 index, thread_index; mp = (session_reset_reply_msg_t *) data; app = application_lookup (mp->context); if (!app) return; - session_parse_handle (mp->handle, &index, &thread_index); - s = session_get_if_valid (index, thread_index); + s = session_get_from_handle_if_valid (mp->handle); /* No session or not the right session */ if (!s || s->session_state < SESSION_STATE_TRANSPORT_CLOSING) @@ -632,6 +607,7 @@ session_mq_worker_update_handler (void *data) session_event_t *evt; session_t *s; application_t *app; + int rv; app = application_lookup (mp->client_index); if (!app) @@ -668,7 +644,9 @@ session_mq_worker_update_handler (void *data) return; } - app_worker_own_session (app_wrk, s); + rv = app_worker_own_session (app_wrk, s); + if (rv) + session_stat_error_inc (rv, 1); /* * Send reply @@ -695,7 +673,7 @@ session_mq_worker_update_handler (void *data) session_send_io_evt_to_thread (s->tx_fifo, SESSION_IO_EVT_TX); if (s->rx_fifo && !svm_fifo_is_empty (s->rx_fifo)) - app_worker_lock_and_send_event (app_wrk, s, SESSION_IO_EVT_RX); + app_worker_rx_notify (app_wrk, s); if (s->session_state >= SESSION_STATE_TRANSPORT_CLOSING) app_worker_close_notify (app_wrk, s); @@ -812,6 +790,9 @@ session_wrk_handle_evts_main_rpc (void *args) case SESSION_CTRL_EVT_ACCEPTED_REPLY: session_mq_accepted_reply_handler (fwrk, elt); break; + case SESSION_CTRL_EVT_CONNECT: + session_mq_connect_handler (fwrk, elt); + break; default: clib_warning ("unhandled %u", elt->evt.event_type); ALWAYS_ASSERT (0); @@ -820,8 +801,11 @@ session_wrk_handle_evts_main_rpc (void *args) /* Regrab element in case pool moved */ elt = clib_llist_elt (fwrk->event_elts, ei); - session_evt_ctrl_data_free (fwrk, elt); - clib_llist_put (fwrk->event_elts, elt); + if (!clib_llist_elt_is_linked (elt, evt_list)) + { + session_evt_ctrl_data_free (fwrk, elt); + clib_llist_put (fwrk->event_elts, elt); + } ei = next_ei; } @@ -1125,8 +1109,8 @@ session_tx_fill_buffer (session_worker_t *wrk, session_tx_context_t *ctx, if (transport_connection_is_cless (ctx->tc)) { - ip_copy (&ctx->tc->rmt_ip, &hdr->rmt_ip, ctx->tc->is_ip4); - ctx->tc->rmt_port = hdr->rmt_port; + clib_memcpy_fast (data0 - sizeof (session_dgram_hdr_t), hdr, + sizeof (*hdr)); } hdr->data_offset += n_bytes_read; if (hdr->data_offset == hdr->data_length) @@ -1188,6 +1172,11 @@ session_tx_not_ready (session_t * s, u8 peek_data) return 2; } } + else + { + if (s->session_state == SESSION_STATE_TRANSPORT_DELETED) + return 2; + } return 0; } @@ -1244,9 +1233,28 @@ session_tx_set_dequeue_params (vlib_main_t * vm, session_tx_context_t * ctx, svm_fifo_peek (ctx->s->tx_fifo, 0, sizeof (ctx->hdr), (u8 *) & ctx->hdr); + /* Zero length dgrams not supported */ + if (PREDICT_FALSE (ctx->hdr.data_length == 0)) + { + svm_fifo_dequeue_drop (ctx->s->tx_fifo, sizeof (ctx->hdr)); + ctx->max_len_to_snd = 0; + return; + } + /* We cannot be sure apps have not enqueued incomplete dgrams */ + if (PREDICT_FALSE (ctx->max_dequeue < + ctx->hdr.data_length + sizeof (ctx->hdr))) + { + ctx->max_len_to_snd = 0; + return; + } ASSERT (ctx->hdr.data_length > ctx->hdr.data_offset); len = ctx->hdr.data_length - ctx->hdr.data_offset; + if (ctx->hdr.gso_size) + { + ctx->sp.snd_mss = clib_min (ctx->sp.snd_mss, ctx->hdr.gso_size); + } + /* Process multiple dgrams if smaller than min (buf_space, mss). * This avoids handling multiple dgrams if they require buffer * chains */ @@ -1266,11 +1274,13 @@ session_tx_set_dequeue_params (vlib_main_t * vm, session_tx_context_t * ctx, { svm_fifo_peek (ctx->s->tx_fifo, offset, sizeof (ctx->hdr), (u8 *) & hdr); - ASSERT (hdr.data_length > hdr.data_offset); dgram_len = hdr.data_length - hdr.data_offset; - if (len + dgram_len > ctx->max_dequeue - || first_dgram_len != dgram_len) + if (offset + sizeof (hdr) + hdr.data_length > + ctx->max_dequeue || + first_dgram_len != dgram_len) break; + /* Assert here to allow test above with zero length dgrams */ + ASSERT (hdr.data_length > hdr.data_offset); len += dgram_len; offset += sizeof (hdr) + hdr.data_length; } @@ -1408,9 +1418,12 @@ session_tx_fifo_read_and_snd_i (session_worker_t * wrk, ctx->sp.max_burst_size = max_burst; n_custom_tx = ctx->transport_vft->custom_tx (ctx->tc, &ctx->sp); *n_tx_packets += n_custom_tx; - if (PREDICT_FALSE - (ctx->s->session_state >= SESSION_STATE_TRANSPORT_CLOSED)) - return SESSION_TX_OK; + if (PREDICT_FALSE (ctx->s->session_state >= + SESSION_STATE_TRANSPORT_CLOSED)) + { + svm_fifo_unset_event (ctx->s->tx_fifo); + return SESSION_TX_OK; + } max_burst -= n_custom_tx; if (!max_burst || (ctx->s->flags & SESSION_F_CUSTOM_TX)) { @@ -1597,9 +1610,12 @@ session_tx_fifo_dequeue_internal (session_worker_t * wrk, { transport_send_params_t *sp = &wrk->ctx.sp; session_t *s = wrk->ctx.s; + clib_llist_index_t ei; u32 n_packets; - if (PREDICT_FALSE (s->session_state >= SESSION_STATE_TRANSPORT_CLOSED)) + if (PREDICT_FALSE ((s->session_state >= SESSION_STATE_TRANSPORT_CLOSED) || + (s->session_state == SESSION_STATE_CONNECTING && + (s->flags & SESSION_F_HALF_OPEN)))) return 0; /* Clear custom-tx flag used to request reschedule for tx */ @@ -1610,9 +1626,14 @@ session_tx_fifo_dequeue_internal (session_worker_t * wrk, sp->max_burst_size = clib_min (SESSION_NODE_FRAME_SIZE - *n_tx_packets, TRANSPORT_PACER_MAX_BURST_PKTS); + /* Grab elt index since app transports can enqueue events on tx */ + ei = clib_llist_entry_index (wrk->event_elts, elt); + n_packets = transport_custom_tx (session_get_transport_proto (s), s, sp); *n_tx_packets += n_packets; + elt = clib_llist_elt (wrk->event_elts, ei); + if (s->flags & SESSION_F_CUSTOM_TX) { session_evt_add_old (wrk, elt); @@ -1767,7 +1788,7 @@ session_event_dispatch_io (session_worker_t * wrk, vlib_node_runtime_t * node, break; case SESSION_IO_EVT_RX: s = session_event_get_session (wrk, e); - if (!s) + if (!s || s->session_state >= SESSION_STATE_TRANSPORT_CLOSED) break; transport_app_rx_evt (session_get_transport_proto (s), s->connection_index, s->thread_index); @@ -1778,13 +1799,15 @@ session_event_dispatch_io (session_worker_t * wrk, vlib_node_runtime_t * node, break; svm_fifo_unset_event (s->rx_fifo); app_wrk = app_worker_get (s->app_wrk_index); - app_worker_builtin_rx (app_wrk, s); + app_worker_rx_notify (app_wrk, s); break; - case SESSION_IO_EVT_BUILTIN_TX: - s = session_get_from_handle_if_valid (e->session_handle); + case SESSION_IO_EVT_TX_MAIN: + s = session_get_if_valid (e->session_index, 0 /* main thread */); + if (PREDICT_FALSE (!s)) + break; wrk->ctx.s = s; if (PREDICT_TRUE (s != 0)) - session_tx_fifo_dequeue_internal (wrk, node, elt, n_tx_packets); + (smm->session_tx_fns[s->session_type]) (wrk, node, elt, n_tx_packets); break; default: clib_warning ("unhandled event type %d", e->event_type); @@ -1798,14 +1821,12 @@ session_event_dispatch_io (session_worker_t * wrk, vlib_node_runtime_t * node, clib_llist_put (wrk->event_elts, elt); } -/* *INDENT-OFF* */ static const u32 session_evt_msg_sizes[] = { #define _(symc, sym) \ [SESSION_CTRL_EVT_ ## symc] = sizeof (session_ ## sym ##_msg_t), foreach_session_ctrl_evt #undef _ }; -/* *INDENT-ON* */ always_inline void session_update_time_subscribers (session_main_t *smm, clib_time_type_t now, @@ -1882,7 +1903,7 @@ session_wrk_update_state (session_worker_t *wrk) if (wrk->state == SESSION_WRK_POLLING) { - if (clib_llist_elts (wrk->event_elts) == 4 && + if (clib_llist_elts (wrk->event_elts) == 5 && vlib_last_vectors_per_main_loop (vm) < 1) { session_wrk_set_state (wrk, SESSION_WRK_INTERRUPT); @@ -1892,7 +1913,7 @@ session_wrk_update_state (session_worker_t *wrk) } else if (wrk->state == SESSION_WRK_INTERRUPT) { - if (clib_llist_elts (wrk->event_elts) > 4 || + if (clib_llist_elts (wrk->event_elts) > 5 || vlib_last_vectors_per_main_loop (vm) > 1) { session_wrk_set_state (wrk, SESSION_WRK_POLLING); @@ -1940,6 +1961,8 @@ session_queue_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, if (wrk->trans_head == ((wrk->trans_tail + 1) & (wrk->trans_size - 1))) return 0; wrk->batch = vlib_dma_batch_new (vm, wrk->config_index); + if (!wrk->batch) + return 0; } /* @@ -2041,7 +2064,6 @@ session_queue_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, return n_tx_packets; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (session_queue_node) = { .function = session_queue_node_fn, .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED, @@ -2052,7 +2074,6 @@ VLIB_REGISTER_NODE (session_queue_node) = { .error_counters = session_error_counters, .state = VLIB_NODE_STATE_DISABLED, }; -/* *INDENT-ON* */ static clib_error_t * session_wrk_tfd_read_ready (clib_file_t *cf) @@ -2156,7 +2177,6 @@ session_queue_process (vlib_main_t * vm, vlib_node_runtime_t * rt, return 0; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (session_queue_process_node) = { .function = session_queue_process, @@ -2164,7 +2184,6 @@ VLIB_REGISTER_NODE (session_queue_process_node) = .name = "session-queue-process", .state = VLIB_NODE_STATE_DISABLED, }; -/* *INDENT-ON* */ static_always_inline uword session_queue_pre_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, @@ -2177,7 +2196,6 @@ session_queue_pre_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, return session_queue_node_fn (vm, node, frame); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (session_queue_pre_input_node) = { .function = session_queue_pre_input_inline, @@ -2185,7 +2203,6 @@ VLIB_REGISTER_NODE (session_queue_pre_input_node) = .name = "session-queue-main", .state = VLIB_NODE_STATE_DISABLED, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON