diff options
author | 2025-03-07 08:02:42 -0500 | |
---|---|---|
committer | 2025-03-24 17:03:48 +0000 | |
commit | 8e50ec8dcadc33f057a621efbfdc948fd414784e (patch) | |
tree | e595359420cf0e92c742fe882fb20f82ebee6c35 /src | |
parent | 7aebf804fe0050d4a48aab591b55f026e8dcc4c4 (diff) |
http: extendable conn/req ctx and multiplexing
multiplexing support:
- set request index as connection_index in application session
- do not allocate app session/http req immediately in
http_ts_accept_callback but wait for request/stream opening
HTTP version specific data in connection and request ctx:
- opaque pointer in http_conn_t
- req_pool manged entirely by specific version engine
Version specific configuration:
- added name to http_engine_vft_t
- added unformat_cfg_callback (optional) to http_engine_vft_t
Type: improvement
Change-Id: Ib43f0489337a222a68b0f81d45cb2e64b2c606c0
Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/http/http.c | 382 | ||||
-rw-r--r-- | src/plugins/http/http1.c | 279 | ||||
-rw-r--r-- | src/plugins/http/http_private.h | 308 | ||||
-rw-r--r-- | src/plugins/http/http_timer.h | 8 |
4 files changed, 614 insertions, 363 deletions
diff --git a/src/plugins/http/http.c b/src/plugins/http/http.c index fc5b7d5d72d..5998a9ebd18 100644 --- a/src/plugins/http/http.c +++ b/src/plugins/http/http.c @@ -36,26 +36,6 @@ http_register_engine (const http_engine_vft_t *vft, http_version_t version) http_vfts[version] = *vft; } -always_inline http_version_t -http_version_from_handle (http_conn_handle_t hc_handle) -{ - /* the first 3 bits are http version */ - return hc_handle >> 29; -} - -always_inline u32 -http_conn_index_from_handle (http_conn_handle_t hc_handle) -{ - return hc_handle & 0x1FFFFFFF; -} - -always_inline http_conn_handle_t -http_make_handle (u32 hc_index, http_version_t version) -{ - ASSERT (hc_index <= 0x1FFFFFFF); - return (version << 29) | hc_index; -} - int http_v_find_index (u8 *vec, u32 offset, u32 num, char *str) { @@ -145,13 +125,7 @@ http_conn_alloc_w_thread (u32 thread_index) http_conn_t *hc; pool_get_aligned_safe (wrk->conn_pool, hc, CLIB_CACHE_LINE_BYTES); - clib_memset (hc, 0, sizeof (*hc)); - hc->c_thread_index = thread_index; - hc->h_hc_index = hc - wrk->conn_pool; - hc->h_pa_session_handle = SESSION_INVALID_HANDLE; - hc->h_tc_session_handle = SESSION_INVALID_HANDLE; - hc->version = HTTP_VERSION_NA; - return hc->h_hc_index; + return (hc - wrk->conn_pool); } static inline http_conn_t * @@ -211,7 +185,7 @@ http_ho_try_free (u32 ho_hc_index) if (!(ho_hc->flags & HTTP_CONN_F_HO_DONE)) { HTTP_DBG (1, "postponed cleanup"); - ho_hc->h_tc_session_handle = SESSION_INVALID_HANDLE; + ho_hc->hc_tc_session_handle = SESSION_INVALID_HANDLE; http_add_postponed_ho_cleanups (ho_hc_index); return; } @@ -247,12 +221,12 @@ http_ho_conn_alloc (void) pool_get_aligned_safe (hm->ho_conn_pool, hc, CLIB_CACHE_LINE_BYTES); clib_memset (hc, 0, sizeof (*hc)); - hc->h_hc_index = hc - hm->ho_conn_pool; - hc->h_pa_session_handle = SESSION_INVALID_HANDLE; - hc->h_tc_session_handle = SESSION_INVALID_HANDLE; + hc->hc_hc_index = hc - hm->ho_conn_pool; + hc->hc_pa_session_handle = SESSION_INVALID_HANDLE; + hc->hc_tc_session_handle = SESSION_INVALID_HANDLE; hc->timeout = HTTP_CONN_TIMEOUT; hc->version = HTTP_VERSION_NA; - return hc->h_hc_index; + return hc->hc_hc_index; } static u32 @@ -262,10 +236,10 @@ http_listener_alloc (void) http_conn_t *lhc; pool_get_zero (hm->listener_pool, lhc); - lhc->h_hc_index = lhc - hm->listener_pool; + lhc->hc_hc_index = lhc - hm->listener_pool; lhc->timeout = HTTP_CONN_TIMEOUT; lhc->version = HTTP_VERSION_NA; - return lhc->h_hc_index; + return lhc->hc_hc_index; } static http_conn_t * @@ -289,7 +263,7 @@ void http_disconnect_transport (http_conn_t *hc) { vnet_disconnect_args_t a = { - .handle = hc->h_tc_session_handle, + .handle = hc->hc_tc_session_handle, .app_index = http_main.app_index, }; @@ -307,14 +281,14 @@ http_sc_by_u16 (u16 status_code) } u8 * -http_get_app_header_list (http_conn_t *hc, http_msg_t *msg) +http_get_app_header_list (http_req_t *req, http_msg_t *msg) { http_main_t *hm = &http_main; session_t *as; u8 *app_headers; int rv; - as = session_get_from_handle (hc->h_pa_session_handle); + as = session_get_from_handle (req->hr_pa_session_handle); if (msg->data.type == HTTP_MSG_DATA_PTR) { @@ -326,7 +300,7 @@ http_get_app_header_list (http_conn_t *hc, http_msg_t *msg) } else { - app_headers = hm->app_header_lists[hc->c_thread_index]; + app_headers = hm->app_header_lists[as->thread_index]; rv = svm_fifo_dequeue (as->tx_fifo, msg->data.headers_len, app_headers); ASSERT (rv == msg->data.headers_len); } @@ -341,7 +315,7 @@ http_get_app_target (http_req_t *req, http_msg_t *msg) u8 *target; int rv; - as = session_get_from_handle (req->app_session_handle); + as = session_get_from_handle (req->hr_pa_session_handle); if (msg->data.type == HTTP_MSG_DATA_PTR) { @@ -384,7 +358,7 @@ http_get_rx_buf (http_conn_t *hc) void http_req_tx_buffer_init (http_req_t *req, http_msg_t *msg) { - session_t *as = session_get_from_handle (req->app_session_handle); + session_t *as = session_get_from_handle (req->hr_pa_session_handle); http_buffer_init (&req->tx_buf, msg_to_buf_type[msg->data.type], as->tx_fifo, msg->data.body_len); } @@ -431,7 +405,7 @@ http_conn_timeout_cb (void *hc_handlep) return; } - session_transport_closing_notify (&hc->connection); + http_vfts[hc->version].transport_close_callback (hc); http_disconnect_transport (hc); } @@ -442,11 +416,10 @@ http_conn_timeout_cb (void *hc_handlep) int http_ts_accept_callback (session_t *ts) { - session_t *ts_listener, *as, *asl; - app_worker_t *app_wrk; + session_t *ts_listener; http_conn_t *lhc, *hc; u32 hc_index, thresh; - int rv; + http_conn_handle_t hc_handle; ts_listener = listen_session_get_from_handle (ts->listener_handle); lhc = http_listener_get (ts_listener->opaque); @@ -456,61 +429,27 @@ http_ts_accept_callback (session_t *ts) clib_memcpy_fast (hc, lhc, sizeof (*lhc)); hc->timer_handle = HTTP_TIMER_HANDLE_INVALID; hc->c_thread_index = ts->thread_index; - hc->h_hc_index = hc_index; - - hc->h_tc_session_handle = session_handle (ts); + hc->hc_hc_index = hc_index; + hc->flags |= HTTP_CONN_F_NO_APP_SESSION; + hc->hc_tc_session_handle = session_handle (ts); hc->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP; hc->state = HTTP_CONN_STATE_ESTABLISHED; ts->session_state = SESSION_STATE_READY; - /* TODO: TLS set by ALPN result, TCP: first try HTTP/1 */ + /* TODO: TLS set by ALPN result, TCP: will decide in http_ts_rx_callback */ hc->version = HTTP_VERSION_1; - ts->opaque = http_make_handle (hc_index, hc->version); - - /* - * Alloc session and initialize - */ - as = session_alloc (hc->c_thread_index); - hc->c_s_index = as->session_index; - - as->app_wrk_index = hc->h_pa_wrk_index; - as->connection_index = hc->h_hc_index; - as->session_state = SESSION_STATE_ACCEPTING; - - asl = listen_session_get_from_handle (lhc->h_pa_session_handle); - as->session_type = asl->session_type; - as->listener_handle = lhc->h_pa_session_handle; - - /* - * Init session fifos and notify app - */ - if ((rv = app_worker_init_accepted (as))) - { - HTTP_DBG (1, "failed to allocate fifos"); - hc->h_pa_session_handle = SESSION_INVALID_HANDLE; - session_free (as); - return rv; - } - - hc->h_pa_session_handle = session_handle (as); - hc->h_pa_wrk_index = as->app_wrk_index; - app_wrk = app_worker_get (as->app_wrk_index); + hc_handle.version = hc->version; + hc_handle.conn_index = hc_index; + ts->opaque = hc_handle.as_u32; HTTP_DBG (1, "Accepted on listener %u new connection [%u]%x", ts_listener->opaque, vlib_get_thread_index (), hc_index); - if ((rv = app_worker_accept_notify (app_wrk, as))) - { - HTTP_DBG (0, "app accept returned"); - session_free (as); - return rv; - } - /* Avoid enqueuing small chunks of data on transport tx notifications. If * the fifo is small (under 16K) we set the threshold to it's size, meaning * a notification will be given when the fifo empties. */ - ts = session_get_from_handle (hc->h_tc_session_handle); + ts = session_get_from_handle (hc->hc_tc_session_handle); thresh = clib_min (svm_fifo_size (ts->tx_fifo), HTTP_FIFO_THRESH); svm_fifo_set_deq_thresh (ts->tx_fifo, thresh); @@ -524,9 +463,9 @@ http_ts_connected_callback (u32 http_app_index, u32 ho_hc_index, session_t *ts, session_error_t err) { u32 new_hc_index; - session_t *as; http_conn_t *hc, *ho_hc; app_worker_t *app_wrk; + http_conn_handle_t hc_handle; int rv; ho_hc = http_ho_conn_get (ho_hc_index); @@ -537,9 +476,9 @@ http_ts_connected_callback (u32 http_app_index, u32 ho_hc_index, session_t *ts, clib_warning ("half-open hc index %d, error: %U", ho_hc_index, format_session_error, err); ho_hc->flags |= HTTP_CONN_F_HO_DONE; - app_wrk = app_worker_get_if_valid (ho_hc->h_pa_wrk_index); + app_wrk = app_worker_get_if_valid (ho_hc->hc_pa_wrk_index); if (app_wrk) - app_worker_connect_notify (app_wrk, 0, err, ho_hc->h_pa_app_api_ctx); + app_worker_connect_notify (app_wrk, 0, err, ho_hc->hc_pa_app_api_ctx); return 0; } @@ -553,43 +492,26 @@ http_ts_connected_callback (u32 http_app_index, u32 ho_hc_index, session_t *ts, hc->timer_handle = HTTP_TIMER_HANDLE_INVALID; hc->c_thread_index = ts->thread_index; - hc->h_tc_session_handle = session_handle (ts); - hc->h_hc_index = new_hc_index; + hc->hc_tc_session_handle = session_handle (ts); + hc->hc_hc_index = new_hc_index; hc->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP; hc->state = HTTP_CONN_STATE_ESTABLISHED; ts->session_state = SESSION_STATE_READY; + hc->flags |= HTTP_CONN_F_NO_APP_SESSION; /* TODO: TLS set by ALPN result, TCP: prior knowledge (set in ho) */ - ts->opaque = http_make_handle (new_hc_index, hc->version); - - /* allocate app session and initialize */ - - as = session_alloc (hc->c_thread_index); - hc->c_s_index = as->session_index; - as->connection_index = new_hc_index; - as->app_wrk_index = hc->h_pa_wrk_index; - as->session_state = SESSION_STATE_READY; - as->opaque = hc->h_pa_app_api_ctx; - as->session_type = session_type_from_proto_and_ip ( - TRANSPORT_PROTO_HTTP, session_type_is_ip4 (ts->session_type)); + hc_handle.version = hc->version; + hc_handle.conn_index = new_hc_index; + ts->opaque = hc_handle.as_u32; HTTP_DBG (1, "half-open hc index %x, hc [%u]%x", ho_hc_index, ts->thread_index, new_hc_index); - app_wrk = app_worker_get (hc->h_pa_wrk_index); - if (!app_wrk) - { - clib_warning ("no app worker"); - return -1; - } - - if ((rv = app_worker_init_connected (app_wrk, as))) + if ((rv = http_vfts[hc->version].transport_connected_callback (hc))) { - HTTP_DBG (1, "failed to allocate fifos"); - session_free (as); + clib_warning ("transport_connected_callback failed, rv=%d", rv); return rv; } - app_worker_connect_notify (app_wrk, as, err, hc->h_pa_app_api_ctx); - hc->h_pa_session_handle = session_handle (as); + http_conn_timer_start (hc); return 0; @@ -599,11 +521,13 @@ static void http_ts_disconnect_callback (session_t *ts) { http_conn_t *hc; - u32 hc_index = http_conn_index_from_handle (ts->opaque); + http_conn_handle_t hc_handle; + + hc_handle.as_u32 = ts->opaque; HTTP_DBG (1, "hc [%u]%x", ts->thread_index, hc_index); - hc = http_conn_get_w_thread (hc_index, ts->thread_index); + hc = http_conn_get_w_thread (hc_handle.conn_index, ts->thread_index); if (hc->state < HTTP_CONN_STATE_TRANSPORT_CLOSED) hc->state = HTTP_CONN_STATE_TRANSPORT_CLOSED; @@ -615,14 +539,16 @@ static void http_ts_reset_callback (session_t *ts) { http_conn_t *hc; - u32 hc_index = http_conn_index_from_handle (ts->opaque); + http_conn_handle_t hc_handle; + + hc_handle.as_u32 = ts->opaque; HTTP_DBG (1, "hc [%u]%x", ts->thread_index, hc_index); - hc = http_conn_get_w_thread (hc_index, ts->thread_index); + hc = http_conn_get_w_thread (hc_handle.conn_index, ts->thread_index); hc->state = HTTP_CONN_STATE_CLOSED; - session_transport_reset_notify (&hc->connection); + http_vfts[hc->version].transport_reset_callback (hc); http_disconnect_transport (hc); } @@ -631,11 +557,13 @@ static int http_ts_rx_callback (session_t *ts) { http_conn_t *hc; - u32 hc_index = http_conn_index_from_handle (ts->opaque); + http_conn_handle_t hc_handle; - HTTP_DBG (1, "hc [%u]%x", ts->thread_index, hc_index); + hc_handle.as_u32 = ts->opaque; - hc = http_conn_get_w_thread (hc_index, ts->thread_index); + HTTP_DBG (1, "hc [%u]%x", ts->thread_index, hc_handle.conn_index); + + hc = http_conn_get_w_thread (hc_handle.conn_index, ts->thread_index); if (hc->state == HTTP_CONN_STATE_CLOSED) { @@ -644,13 +572,11 @@ http_ts_rx_callback (session_t *ts) return 0; } - http_vfts[http_version_from_handle (ts->opaque)].transport_rx_callback (hc); + /* TODO: if version is unknown */ + http_vfts[hc_handle.version].transport_rx_callback (hc); if (hc->state == HTTP_CONN_STATE_TRANSPORT_CLOSED) - { - if (!svm_fifo_max_dequeue_cons (ts->rx_fifo)) - session_transport_closing_notify (&hc->connection); - } + http_vfts[hc->version].transport_close_callback (hc); return 0; } @@ -658,11 +584,13 @@ int http_ts_builtin_tx_callback (session_t *ts) { http_conn_t *hc; + http_conn_handle_t hc_handle; - hc = http_conn_get_w_thread (http_conn_index_from_handle (ts->opaque), - ts->thread_index); + hc_handle.as_u32 = ts->opaque; + + hc = http_conn_get_w_thread (hc_handle.conn_index, ts->thread_index); HTTP_DBG (1, "transport connection reschedule"); - transport_connection_reschedule (&hc->connection); + http_vfts[hc->version].transport_conn_reschedule_callback (hc); return 0; } @@ -671,29 +599,20 @@ static void http_ts_cleanup_callback (session_t *ts, session_cleanup_ntf_t ntf) { http_conn_t *hc; - http_req_t *req; - u32 hc_index; + http_conn_handle_t hc_handle; if (ntf == SESSION_CLEANUP_TRANSPORT) return; - hc_index = http_conn_index_from_handle (ts->opaque); - hc = http_conn_get_w_thread (hc_index, ts->thread_index); + hc_handle.as_u32 = ts->opaque; + hc = http_conn_get_w_thread (hc_handle.conn_index, ts->thread_index); HTTP_DBG (1, "going to free hc [%u]%x", ts->thread_index, hc_index); - pool_foreach (req, hc->req_pool) - { - vec_free (req->headers); - vec_free (req->target); - http_buffer_free (&req->tx_buf); - } - pool_free (hc->req_pool); - if (!(hc->flags & HTTP_CONN_F_PENDING_TIMER)) http_conn_timer_stop (hc); - session_transport_delete_notify (&hc->connection); + http_vfts[hc->version].conn_cleanup_callback (hc); if (!(hc->flags & HTTP_CONN_F_IS_SERVER)) { @@ -706,9 +625,8 @@ http_ts_cleanup_callback (session_t *ts, session_cleanup_ntf_t ntf) static void http_ts_ho_cleanup_callback (session_t *ts) { - u32 ho_hc_index = http_conn_index_from_handle (ts->opaque); - HTTP_DBG (1, "half open: %x", ho_hc_index); - http_ho_try_free (ho_hc_index); + HTTP_DBG (1, "half open: %x", ts->opaque); + http_ho_try_free (ts->opaque); } int @@ -750,6 +668,7 @@ http_transport_enable (vlib_main_t *vm, u8 is_en) u64 options[APP_OPTIONS_N_OPTIONS]; http_main_t *hm = &http_main; u32 num_threads, i; + http_engine_vft_t *http_version; if (!is_en) { @@ -806,6 +725,12 @@ http_transport_enable (vlib_main_t *vm, u8 is_en) http_timers_init (vm, http_conn_timeout_cb, http_conn_invalidate_timer_cb); hm->is_init = 1; + vec_foreach (http_version, http_vfts) + { + if (http_version->enable_callback) + http_version->enable_callback (); + } + return 0; } @@ -832,10 +757,10 @@ http_transport_connect (transport_endpoint_cfg_t *tep) hc_index = http_ho_conn_alloc (); hc = http_ho_conn_get (hc_index); - hc->h_pa_wrk_index = sep->app_wrk_index; - hc->h_pa_app_api_ctx = sep->opaque; + hc->hc_pa_wrk_index = sep->app_wrk_index; + hc->hc_pa_app_api_ctx = sep->opaque; hc->state = HTTP_CONN_STATE_CONNECTING; - /* TODO: set to HTTP_VERSION_NA in case of TLS (when supported) */ + /* TODO: set to HTTP_VERSION_NA in case of TLS */ hc->version = HTTP_VERSION_1; cargs->api_context = hc_index; @@ -878,7 +803,7 @@ http_transport_connect (transport_endpoint_cfg_t *tep) ho->opaque = sep->opaque; ho->session_type = session_type_from_proto_and_ip (TRANSPORT_PROTO_HTTP, sep->is_ip4); - hc->h_tc_session_handle = cargs->sh; + hc->hc_tc_session_handle = cargs->sh; hc->c_s_index = ho->session_index; return 0; @@ -933,15 +858,15 @@ http_start_listen (u32 app_listener_index, transport_endpoint_cfg_t *tep) } /* Grab transport connection listener and link to http listener */ - lhc->h_tc_session_handle = args->handle; - al = app_listener_get_w_handle (lhc->h_tc_session_handle); + lhc->hc_tc_session_handle = args->handle; + al = app_listener_get_w_handle (lhc->hc_tc_session_handle); ts_listener = app_listener_get_session (al); ts_listener->opaque = lhc_index; /* Grab application listener and link to http listener */ app_listener = listen_session_get (app_listener_index); - lhc->h_pa_wrk_index = sep->app_wrk_index; - lhc->h_pa_session_handle = listen_session_get_handle (app_listener); + lhc->hc_pa_wrk_index = sep->app_wrk_index; + lhc->hc_pa_session_handle = listen_session_get_handle (app_listener); lhc->c_s_index = app_listener_index; lhc->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP; @@ -964,7 +889,7 @@ http_stop_listen (u32 listener_index) lhc = http_listener_get (listener_index); vnet_unlisten_args_t a = { - .handle = lhc->h_tc_session_handle, + .handle = lhc->hc_tc_session_handle, .app_index = http_main.app_index, .wrk_map_index = 0 /* default wrk */ }; @@ -978,15 +903,22 @@ http_stop_listen (u32 listener_index) } static void -http_transport_close (u32 hc_index, u32 thread_index) +http_transport_close (u32 rh, u32 thread_index) { http_conn_t *hc; + u32 hc_index; + http_req_handle_t hr_handle; + hr_handle.as_u32 = rh; + + hc_index = http_vfts[hr_handle.version].hc_index_get_by_req_index ( + hr_handle.req_index, thread_index); HTTP_DBG (1, "App disconnecting [%u]%x", thread_index, hc_index); hc = http_conn_get_w_thread (hc_index, thread_index); if (hc->state == HTTP_CONN_STATE_CONNECTING) { + HTTP_DBG (1, "in connecting state, close now"); hc->state = HTTP_CONN_STATE_APP_CLOSED; http_disconnect_transport (hc); return; @@ -997,14 +929,20 @@ http_transport_close (u32 hc_index, u32 thread_index) return; } - http_vfts[hc->version].app_close_callback (hc); + http_vfts[hc->version].app_close_callback (hc, hr_handle.req_index, + thread_index); } static void -http_transport_reset (u32 hc_index, u32 thread_index) +http_transport_reset (u32 rh, u32 thread_index) { http_conn_t *hc; + u32 hc_index; + http_req_handle_t hr_handle; + hr_handle.as_u32 = rh; + hc_index = http_vfts[hr_handle.version].hc_index_get_by_req_index ( + hr_handle.req_index, thread_index); HTTP_DBG (1, "App disconnecting [%u]%x", thread_index, hc_index); hc = http_conn_get_w_thread (hc_index, thread_index); @@ -1014,14 +952,18 @@ http_transport_reset (u32 hc_index, u32 thread_index) return; } - http_vfts[hc->version].app_reset_callback (hc); + http_vfts[hc->version].app_reset_callback (hc, hr_handle.req_index, + thread_index); } static transport_connection_t * -http_transport_get_connection (u32 hc_index, u32 thread_index) +http_transport_get_connection (u32 rh, u32 thread_index) { - http_conn_t *hc = http_conn_get_w_thread (hc_index, thread_index); - return &hc->connection; + http_req_handle_t hr_handle; + + hr_handle.as_u32 = rh; + return http_vfts[hr_handle.version].req_get_connection (hr_handle.req_index, + thread_index); } static transport_connection_t * @@ -1035,12 +977,16 @@ static int http_app_tx_callback (void *session, transport_send_params_t *sp) { session_t *as = (session_t *) session; - u32 max_burst_sz, sent; + u32 max_burst_sz, sent, hc_index; http_conn_t *hc; + http_req_handle_t hr_handle; + hr_handle.as_u32 = as->connection_index; - HTTP_DBG (1, "hc [%u]%x", as->thread_index, as->connection_index); + hc_index = http_vfts[hr_handle.version].hc_index_get_by_req_index ( + hr_handle.req_index, as->thread_index); + HTTP_DBG (1, "hc [%u]%x", hc_index, as->connection_index); - hc = http_conn_get_w_thread (as->connection_index, as->thread_index); + hc = http_conn_get_w_thread (hc_index, as->thread_index); if (hc->state == HTTP_CONN_STATE_CLOSED) { @@ -1052,16 +998,11 @@ http_app_tx_callback (void *session, transport_send_params_t *sp) max_burst_sz = sp->max_burst_size * TRANSPORT_PACER_MIN_MSS; sp->max_burst_size = max_burst_sz; - http_vfts[hc->version].app_tx_callback (hc, sp); + http_vfts[hc->version].app_tx_callback (hc, hr_handle.req_index, sp); if (hc->state == HTTP_CONN_STATE_APP_CLOSED) - { - if (!svm_fifo_max_dequeue_cons (as->tx_fifo)) - { - session_transport_closed_notify (&hc->connection); - http_disconnect_transport (hc); - } - } + http_vfts[hc->version].app_close_callback (hc, hr_handle.req_index, + as->thread_index); sent = max_burst_sz - sp->max_burst_size; @@ -1071,37 +1012,36 @@ http_app_tx_callback (void *session, transport_send_params_t *sp) static int http_app_rx_evt_cb (transport_connection_t *tc) { - http_conn_t *hc = (http_conn_t *) tc; - HTTP_DBG (1, "hc [%u]%x", vlib_get_thread_index (), hc->h_hc_index); + http_req_t *req = (http_req_t *) tc; + http_conn_t *hc; + http_req_handle_t hr_handle; + + HTTP_DBG (1, "hc [%u]%x", vlib_get_thread_index (), req->hr_hc_index); - http_vfts[hc->version].app_rx_evt_callback (hc); + hr_handle.as_u32 = req->hr_req_handle; + hc = http_conn_get_w_thread (req->hr_hc_index, req->c_thread_index); + http_vfts[hr_handle.version].app_rx_evt_callback (hc, hr_handle.req_index, + req->c_thread_index); return 0; } static void -http_transport_get_endpoint (u32 hc_index, u32 thread_index, +http_transport_get_endpoint (u32 rh, u32 thread_index, transport_endpoint_t *tep, u8 is_lcl) { - http_conn_t *hc = http_conn_get_w_thread (hc_index, thread_index); - session_t *ts; - - ts = session_get_from_handle (hc->h_tc_session_handle); - session_get_endpoint (ts, tep, is_lcl); -} - -static u8 * -format_http_connection (u8 *s, va_list *args) -{ - http_conn_t *hc = va_arg (*args, http_conn_t *); + http_conn_t *hc; session_t *ts; + u32 hc_index; + http_req_handle_t hr_handle; - ts = session_get_from_handle (hc->h_tc_session_handle); - s = format (s, "[%d:%d][H] app_wrk %u ts %d:%d", hc->c_thread_index, - hc->c_s_index, hc->h_pa_wrk_index, ts->thread_index, - ts->session_index); + hr_handle.as_u32 = rh; + hc_index = http_vfts[hr_handle.version].hc_index_get_by_req_index ( + hr_handle.req_index, thread_index); + hc = http_conn_get_w_thread (hc_index, thread_index); - return s; + ts = session_get_from_handle (hc->hc_tc_session_handle); + session_get_endpoint (ts, tep, is_lcl); } static u8 * @@ -1111,10 +1051,10 @@ format_http_listener (u8 *s, va_list *args) app_listener_t *al; session_t *lts; - al = app_listener_get_w_handle (lhc->h_tc_session_handle); + al = app_listener_get_w_handle (lhc->hc_tc_session_handle); lts = app_listener_get_session (al); s = format (s, "[%d:%d][H] app_wrk %u ts %d:%d", lhc->c_thread_index, - lhc->c_s_index, lhc->h_pa_wrk_index, lts->thread_index, + lhc->c_s_index, lhc->hc_pa_wrk_index, lts->thread_index, lts->session_index); return s; @@ -1123,22 +1063,18 @@ format_http_listener (u8 *s, va_list *args) static u8 * format_http_transport_connection (u8 *s, va_list *args) { - u32 tc_index = va_arg (*args, u32); + http_req_handle_t rh = va_arg (*args, http_req_handle_t); u32 thread_index = va_arg (*args, u32); u32 verbose = va_arg (*args, u32); + u32 hc_index; http_conn_t *hc; - hc = http_conn_get_w_thread (tc_index, thread_index); - - s = format (s, "%-" SESSION_CLI_ID_LEN "U", format_http_connection, hc); - if (verbose) - { - s = - format (s, "%-" SESSION_CLI_STATE_LEN "U", format_http_conn_state, hc); - if (verbose > 1) - s = format (s, "\n"); - } + hc_index = http_vfts[rh.version].hc_index_get_by_req_index (rh.req_index, + thread_index); + hc = http_conn_get_w_thread (hc_index, thread_index); + s = format (s, "%U", http_vfts[rh.version].format_req, rh.req_index, + thread_index, hc, verbose); return s; } @@ -1167,10 +1103,10 @@ format_http_transport_half_open (u8 *s, va_list *args) session_t *tcp_ho; ho_hc = http_ho_conn_get (ho_index); - tcp_ho = session_get_from_handle (ho_hc->h_tc_session_handle); + tcp_ho = session_get_from_handle (ho_hc->hc_tc_session_handle); s = format (s, "[%d:%d][H] half-open app_wrk %u ts %d:%d", - ho_hc->c_thread_index, ho_hc->c_s_index, ho_hc->h_pa_wrk_index, + ho_hc->c_thread_index, ho_hc->c_s_index, ho_hc->hc_pa_wrk_index, tcp_ho->thread_index, tcp_ho->session_index); return s; } @@ -1192,13 +1128,13 @@ http_transport_cleanup_ho (u32 ho_hc_index) HTTP_DBG (1, "half open: %x", ho_hc_index); ho_hc = http_ho_conn_get (ho_hc_index); - if (ho_hc->h_tc_session_handle == SESSION_INVALID_HANDLE) + if (ho_hc->hc_tc_session_handle == SESSION_INVALID_HANDLE) { HTTP_DBG (1, "already pending cleanup"); ho_hc->flags |= HTTP_CONN_F_NO_APP_SESSION; return; } - session_cleanup_half_open (ho_hc->h_tc_session_handle); + session_cleanup_half_open (ho_hc->hc_tc_session_handle); http_ho_conn_free (ho_hc); } @@ -1267,6 +1203,28 @@ http_transport_init (vlib_main_t *vm) VLIB_INIT_FUNCTION (http_transport_init); +static uword +unformat_http_version_cfg (unformat_input_t *input, va_list *va) +{ + http_engine_vft_t *http_version; + unformat_input_t sub_input; + int found = 0; + + vec_foreach (http_version, http_vfts) + { + if (!unformat (input, http_version->name)) + continue; + + if (http_version->unformat_cfg_callback && + unformat (input, "%U", unformat_vlib_cli_sub_input, &sub_input)) + { + if (http_version->unformat_cfg_callback (&sub_input)) + found = 1; + } + } + return found; +} + static clib_error_t * http_config_fn (vlib_main_t *vm, unformat_input_t *input) { @@ -1295,6 +1253,8 @@ http_config_fn (vlib_main_t *vm, unformat_input_t *input) if (hm->fifo_size != mem_sz) clib_warning ("invalid fifo size %lu", mem_sz); } + else if (unformat (input, "%U", unformat_http_version_cfg)) + ; else return clib_error_return (0, "unknown input `%U'", format_unformat_error, input); diff --git a/src/plugins/http/http1.c b/src/plugins/http/http1.c index c152956e43c..ec118aa4e52 100644 --- a/src/plugins/http/http1.c +++ b/src/plugins/http/http1.c @@ -10,6 +10,13 @@ #include <http/http_status_codes.h> #include <http/http_timer.h> +typedef struct http1_main_ +{ + http_req_t **req_pool; +} http1_main_t; + +static http1_main_t http1_main; + const char *http1_upgrade_proto_str[] = { "", #define _(sym, str) str, foreach_http_upgrade_proto @@ -48,6 +55,76 @@ static const char *post_request_template = "POST %s HTTP/1.1\r\n" "User-Agent: %v\r\n" "Content-Length: %llu\r\n"; +always_inline http_req_t * +http1_conn_alloc_req (http_conn_t *hc) +{ + http1_main_t *h1m = &http1_main; + http_req_t *req; + u32 req_index; + http_req_handle_t hr_handle; + + pool_get_aligned_safe (h1m->req_pool[hc->c_thread_index], req, + CLIB_CACHE_LINE_BYTES); + clib_memset (req, 0, sizeof (*req)); + req->hr_pa_session_handle = SESSION_INVALID_HANDLE; + req_index = req - h1m->req_pool[hc->c_thread_index]; + hr_handle.version = HTTP_VERSION_1; + hr_handle.req_index = req_index; + req->hr_req_handle = hr_handle.as_u32; + req->hr_hc_index = hc->hc_hc_index; + req->c_thread_index = hc->c_thread_index; + req->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP; + hc->opaque = uword_to_pointer (req_index, void *); + hc->flags |= HTTP_CONN_F_HAS_REQUEST; + return req; +} + +always_inline http_req_t * +http1_req_get (u32 req_index, u32 thread_index) +{ + http1_main_t *h1m = &http1_main; + + return pool_elt_at_index (h1m->req_pool[thread_index], req_index); +} + +always_inline http_req_t * +http1_req_get_if_valid (u32 req_index, u32 thread_index) +{ + http1_main_t *h1m = &http1_main; + + if (pool_is_free_index (h1m->req_pool[thread_index], req_index)) + return 0; + return pool_elt_at_index (h1m->req_pool[thread_index], req_index); +} + +always_inline http_req_t * +http1_conn_get_req (http_conn_t *hc) +{ + http1_main_t *h1m = &http1_main; + u32 req_index; + + req_index = pointer_to_uword (hc->opaque); + return pool_elt_at_index (h1m->req_pool[hc->c_thread_index], req_index); +} + +always_inline void +http1_conn_free_req (http_conn_t *hc) +{ + http1_main_t *h1m = &http1_main; + http_req_t *req; + u32 req_index; + + req_index = pointer_to_uword (hc->opaque); + req = pool_elt_at_index (h1m->req_pool[hc->c_thread_index], req_index); + vec_free (req->headers); + vec_free (req->target); + http_buffer_free (&req->tx_buf); + if (CLIB_DEBUG) + memset (req, 0xba, sizeof (*req)); + pool_put (h1m->req_pool[hc->c_thread_index], req); + hc->flags &= ~HTTP_CONN_F_HAS_REQUEST; +} + static void http1_send_error (http_conn_t *hc, http_status_code_t ec, transport_send_params_t *sp) @@ -730,13 +807,13 @@ http1_target_fixup (http_conn_t *hc, http_req_t *req) } static void -http1_write_app_headers (http_conn_t *hc, http_msg_t *msg, u8 **tx_buf) +http1_write_app_headers (http_req_t *req, http_msg_t *msg, u8 **tx_buf) { u8 *app_headers, *p, *end; u32 *tmp; /* read app header list */ - app_headers = http_get_app_header_list (hc, msg); + app_headers = http_get_app_header_list (req, msg); /* serialize app headers to tx_buf */ end = app_headers + msg->data.headers_len; @@ -871,8 +948,8 @@ http1_req_state_wait_transport_reply (http_conn_t *hc, http_req_t *req, error: http_io_ts_drain_all (hc); http_io_ts_after_read (hc, 1); - session_transport_closing_notify (&hc->connection); - session_transport_closed_notify (&hc->connection); + session_transport_closing_notify (&req->connection); + session_transport_closed_notify (&req->connection); http_disconnect_transport (hc); return HTTP_SM_ERROR; } @@ -978,7 +1055,7 @@ error: http_io_ts_drain_all (hc); http_io_ts_after_read (hc, 1); http1_send_error (hc, ec, 0); - session_transport_closing_notify (&hc->connection); + session_transport_closing_notify (&req->connection); http_disconnect_transport (hc); return HTTP_SM_ERROR; @@ -1015,7 +1092,7 @@ http1_req_state_transport_io_more_data (http_conn_t *hc, http_req_t *req, if (n_written > req->to_recv) { clib_warning ("http protocol error: received more data than expected"); - session_transport_closing_notify (&hc->connection); + session_transport_closing_notify (&req->connection); http_disconnect_transport (hc); http_req_state_change (req, HTTP_REQ_STATE_WAIT_APP_METHOD); return HTTP_SM_ERROR; @@ -1117,8 +1194,8 @@ http1_req_state_udp_tunnel_rx (http_conn_t *hc, http_req_t *req, { /* capsule datagram is invalid (session need to be aborted) */ http_io_ts_drain_all (hc); - session_transport_closing_notify (&hc->connection); - session_transport_closed_notify (&hc->connection); + session_transport_closing_notify (&req->connection); + session_transport_closed_notify (&req->connection); http_disconnect_transport (hc); return HTTP_SM_STOP; } @@ -1262,7 +1339,7 @@ http1_req_state_wait_app_reply (http_conn_t *hc, http_req_t *req, if (msg.data.headers_len) { HTTP_DBG (0, "got headers from app, len %d", msg.data.headers_len); - http1_write_app_headers (hc, &msg, &response); + http1_write_app_headers (req, &msg, &response); } /* Add empty line after headers */ response = format (response, "\r\n"); @@ -1297,7 +1374,7 @@ http1_req_state_wait_app_reply (http_conn_t *hc, http_req_t *req, error: http1_send_error (hc, sc, sp); - session_transport_closing_notify (&hc->connection); + session_transport_closing_notify (&req->connection); http_disconnect_transport (hc); return HTTP_SM_STOP; } @@ -1392,7 +1469,7 @@ http1_req_state_wait_app_method (http_conn_t *hc, http_req_t *req, if (msg.data.headers_len) { HTTP_DBG (0, "got headers from app, len %d", msg.data.headers_len); - http1_write_app_headers (hc, &msg, &request); + http1_write_app_headers (req, &msg, &request); } /* Add empty line after headers */ request = format (request, "\r\n"); @@ -1414,8 +1491,8 @@ http1_req_state_wait_app_method (http_conn_t *hc, http_req_t *req, error: http_io_as_drain_all (req); - session_transport_closing_notify (&hc->connection); - session_transport_closed_notify (&hc->connection); + session_transport_closing_notify (&req->connection); + session_transport_closed_notify (&req->connection); http_disconnect_transport (hc); done: @@ -1617,20 +1694,69 @@ http1_req_run_state_machine (http_conn_t *hc, http_req_t *req, /* http core VFT */ /*****************/ -static void -http1_app_tx_callback (http_conn_t *hc, transport_send_params_t *sp) +static u32 +http1_hc_index_get_by_req_index (u32 req_index, u32 thread_index) { http_req_t *req; - req = http_get_req_if_valid (hc, 0); - if (!req) + req = http1_req_get (req_index, thread_index); + return req->hr_hc_index; +} + +static transport_connection_t * +http1_req_get_connection (u32 req_index, u32 thread_index) +{ + http_req_t *req; + req = http1_req_get (req_index, thread_index); + return &req->connection; +} + +static u8 * +format_http1_req (u8 *s, va_list *args) +{ + http_req_t *req = va_arg (*args, http_req_t *); + http_conn_t *hc = va_arg (*args, http_conn_t *); + session_t *ts; + + ts = session_get_from_handle (hc->hc_tc_session_handle); + s = format (s, "[%d:%d][H1] app_wrk %u hc_index %u ts %d:%d", + req->c_thread_index, req->c_s_index, req->hr_pa_wrk_index, + req->hr_hc_index, ts->thread_index, ts->session_index); + + return s; +} + +static u8 * +http1_format_req (u8 *s, va_list *args) +{ + u32 req_index = va_arg (*args, u32); + u32 thread_index = va_arg (*args, u32); + http_conn_t *hc = va_arg (*args, http_conn_t *); + u32 verbose = va_arg (*args, u32); + http_req_t *req; + + req = http1_req_get (req_index, thread_index); + + s = format (s, "%-" SESSION_CLI_ID_LEN "U", format_http1_req, req, hc); + if (verbose) { - http_alloc_req (hc); - req = http_get_req (hc, 0); - req->app_session_handle = hc->h_pa_session_handle; - http_req_state_change (req, HTTP_REQ_STATE_WAIT_APP_METHOD); + s = + format (s, "%-" SESSION_CLI_STATE_LEN "U", format_http_conn_state, hc); + if (verbose > 1) + s = format (s, "\n"); } + return s; +} + +static void +http1_app_tx_callback (http_conn_t *hc, u32 req_index, + transport_send_params_t *sp) +{ + http_req_t *req; + + req = http1_req_get (req_index, hc->c_thread_index); + if (!http1_req_state_is_tx_valid (req)) { /* Sometimes the server apps can send the response earlier @@ -1645,7 +1771,7 @@ http1_app_tx_callback (http_conn_t *hc, transport_send_params_t *sp) { clib_warning ("hc [%u]%x invalid tx state: http req state " "'%U', session state '%U'", - hc->c_thread_index, hc->h_hc_index, + hc->c_thread_index, hc->hc_hc_index, format_http_req_state, req->state, format_http_conn_state, hc); http_io_as_drain_all (req); @@ -1658,26 +1784,32 @@ http1_app_tx_callback (http_conn_t *hc, transport_send_params_t *sp) } static void -http1_app_rx_evt_callback (http_conn_t *hc) +http1_app_rx_evt_callback (http_conn_t *hc, u32 req_index, u32 thread_index) { http_req_t *req; - req = http_get_req (hc, 0); + req = http1_req_get (req_index, thread_index); if (req->state == HTTP_REQ_STATE_TUNNEL) http1_req_state_tunnel_rx (hc, req, 0); } static void -http1_app_close_callback (http_conn_t *hc) +http1_app_close_callback (http_conn_t *hc, u32 req_index, u32 thread_index) { http_req_t *req; - req = http_get_req_if_valid (hc, 0); + req = http1_req_get_if_valid (req_index, thread_index); + if (!req) + { + HTTP_DBG (1, "req already deleted"); + return; + } /* Nothing more to send, confirm close */ - if (!req || !http_io_as_max_read (req)) + if (!http_io_as_max_read (req)) { - session_transport_closed_notify (&hc->connection); + HTTP_DBG (1, "nothing more to send, confirm close"); + session_transport_closed_notify (&req->connection); http_disconnect_transport (hc); } else @@ -1688,31 +1820,48 @@ http1_app_close_callback (http_conn_t *hc) } static void -http1_app_reset_callback (http_conn_t *hc) +http1_app_reset_callback (http_conn_t *hc, u32 req_index, u32 thread_index) { - session_transport_closed_notify (&hc->connection); + http_req_t *req; + req = http1_req_get (req_index, thread_index); + session_transport_closed_notify (&req->connection); http_disconnect_transport (hc); } +static int +http1_transport_connected_callback (http_conn_t *hc) +{ + http_req_t *req; + + ASSERT (hc->flags & HTTP_CONN_F_NO_APP_SESSION); + + req = http1_conn_alloc_req (hc); + http_req_state_change (req, HTTP_REQ_STATE_WAIT_APP_METHOD); + return http_conn_established (hc, req); +} + static void http1_transport_rx_callback (http_conn_t *hc) { http_req_t *req; - req = http_get_req_if_valid (hc, 0); - if (!req) + if (!(hc->flags & HTTP_CONN_F_HAS_REQUEST)) { - http_alloc_req (hc); - req = http_get_req (hc, 0); - req->app_session_handle = hc->h_pa_session_handle; + ASSERT (hc->flags & HTTP_CONN_F_IS_SERVER); + /* first request - create request ctx and notify app about new conn */ + req = http1_conn_alloc_req (hc); + http_conn_accept_request (hc, req); http_req_state_change (req, HTTP_REQ_STATE_WAIT_TRANSPORT_METHOD); + hc->flags &= ~HTTP_CONN_F_NO_APP_SESSION; } + else + req = http1_conn_get_req (hc); if (!http1_req_state_is_rx_valid (req)) { clib_warning ("hc [%u]%x invalid rx state: http req state " "'%U', session state '%U'", - hc->c_thread_index, hc->h_hc_index, format_http_req_state, + hc->c_thread_index, hc->hc_hc_index, format_http_req_state, req->state, format_http_conn_state, hc); http_io_ts_drain_all (hc); return; @@ -1725,18 +1874,74 @@ http1_transport_rx_callback (http_conn_t *hc) static void http1_transport_close_callback (http_conn_t *hc) { + if (!(hc->flags & HTTP_CONN_F_HAS_REQUEST)) + return; /* Nothing more to rx, propagate to app */ if (!http_io_ts_max_read (hc)) - session_transport_closing_notify (&hc->connection); + { + http_req_t *req = http1_conn_get_req (hc); + session_transport_closing_notify (&req->connection); + } +} + +static void +http1_transport_reset_callback (http_conn_t *hc) +{ + if (!(hc->flags & HTTP_CONN_F_HAS_REQUEST)) + return; + http_req_t *req = http1_conn_get_req (hc); + session_transport_reset_notify (&req->connection); +} + +static void +http1_transport_conn_reschedule_callback (http_conn_t *hc) +{ + ASSERT (hc->flags & HTTP_CONN_F_HAS_REQUEST); + http_req_t *req = http1_conn_get_req (hc); + transport_connection_reschedule (&req->connection); +} + +static void +http1_conn_cleanup_callback (http_conn_t *hc) +{ + http_req_t *req; + if (!(hc->flags & HTTP_CONN_F_HAS_REQUEST)) + return; + + req = http1_conn_get_req (hc); + session_transport_delete_notify (&req->connection); + http1_conn_free_req (hc); +} + +static void +http1_enable_callback (void) +{ + http1_main_t *h1m = &http1_main; + vlib_thread_main_t *vtm = vlib_get_thread_main (); + u32 num_threads; + + num_threads = 1 /* main thread */ + vtm->n_threads; + + vec_validate (h1m->req_pool, num_threads - 1); } const static http_engine_vft_t http1_engine = { + .name = "http1", + .hc_index_get_by_req_index = http1_hc_index_get_by_req_index, + .req_get_connection = http1_req_get_connection, + .format_req = http1_format_req, .app_tx_callback = http1_app_tx_callback, .app_rx_evt_callback = http1_app_rx_evt_callback, .app_close_callback = http1_app_close_callback, .app_reset_callback = http1_app_reset_callback, + .transport_connected_callback = http1_transport_connected_callback, .transport_rx_callback = http1_transport_rx_callback, .transport_close_callback = http1_transport_close_callback, + .transport_conn_reschedule_callback = + http1_transport_conn_reschedule_callback, + .transport_reset_callback = http1_transport_reset_callback, + .conn_cleanup_callback = http1_conn_cleanup_callback, + .enable_callback = http1_enable_callback, }; static clib_error_t * diff --git a/src/plugins/http/http_private.h b/src/plugins/http/http_private.h index 154a63d2402..ebec59aeaee 100644 --- a/src/plugins/http/http_private.h +++ b/src/plugins/http/http_private.h @@ -14,21 +14,29 @@ #define HTTP_FIFO_THRESH (16 << 10) -typedef u32 http_conn_handle_t; +typedef union +{ + struct + { + u32 version : 3; + u32 conn_index : 29; + }; + u32 as_u32; +} http_conn_handle_t; -typedef struct http_conn_id_ +STATIC_ASSERT (sizeof (http_conn_handle_t) == sizeof (u32), "must fit in u32"); + +typedef union { - union + struct { - session_handle_t app_session_handle; - u32 parent_app_api_ctx; + u32 version : 3; + u32 req_index : 29; }; - session_handle_t tc_session_handle; - u32 parent_app_wrk_index; -} http_conn_id_t; + u32 as_u32; +} http_req_handle_t; -STATIC_ASSERT (sizeof (http_conn_id_t) <= TRANSPORT_CONN_ID_LEN, - "ctx id must be less than TRANSPORT_CONN_ID_LEN"); +STATIC_ASSERT (sizeof (http_req_handle_t) == sizeof (u32), "must fit in u32"); #define foreach_http_conn_state \ _ (LISTEN, "LISTEN") \ @@ -80,10 +88,28 @@ typedef enum http_version_ HTTP_VERSION_NA = 7, } http_version_t; -typedef struct http_req_ +typedef struct http_req_id_ { - /* in case of multiplexing we have app session for each stream */ session_handle_t app_session_handle; + u32 parent_app_wrk_index; + u32 hc_index; +} http_req_id_t; + +STATIC_ASSERT (sizeof (http_req_id_t) <= TRANSPORT_CONN_ID_LEN, + "ctx id must be less than TRANSPORT_CONN_ID_LEN"); + +typedef struct http_req_ +{ + union + { + transport_connection_t connection; + http_req_id_t c_http_req_id; + }; +#define hr_pa_wrk_index c_http_req_id.parent_app_wrk_index +#define hr_pa_session_handle c_http_req_id.app_session_handle +#define hr_hc_index c_http_req_id.hc_index +#define hr_req_handle connection.c_index + u32 as_fifo_offset; /* for peek */ http_req_state_t state; /* state-machine state */ @@ -142,7 +168,8 @@ typedef struct http_req_ _ (HO_DONE, "ho-done") \ _ (NO_APP_SESSION, "no-app-session") \ _ (PENDING_TIMER, "pending-timer") \ - _ (IS_SERVER, "is-server") + _ (IS_SERVER, "is-server") \ + _ (HAS_REQUEST, "has-request") typedef enum http_conn_flags_bit_ { @@ -158,6 +185,20 @@ typedef enum http_conn_flags_ #undef _ } __clib_packed http_conn_flags_t; +typedef struct http_conn_id_ +{ + union + { + session_handle_t app_session_handle; + u32 parent_app_api_ctx; + }; + session_handle_t tc_session_handle; + u32 parent_app_wrk_index; +} http_conn_id_t; + +STATIC_ASSERT (sizeof (http_conn_id_t) <= TRANSPORT_CONN_ID_LEN, + "ctx id must be less than TRANSPORT_CONN_ID_LEN"); + typedef struct http_tc_ { union @@ -165,11 +206,11 @@ typedef struct http_tc_ transport_connection_t connection; http_conn_id_t c_http_conn_id; }; -#define h_tc_session_handle c_http_conn_id.tc_session_handle -#define h_pa_wrk_index c_http_conn_id.parent_app_wrk_index -#define h_pa_session_handle c_http_conn_id.app_session_handle -#define h_pa_app_api_ctx c_http_conn_id.parent_app_api_ctx -#define h_hc_index connection.c_index +#define hc_tc_session_handle c_http_conn_id.tc_session_handle +#define hc_pa_wrk_index c_http_conn_id.parent_app_wrk_index +#define hc_pa_session_handle c_http_conn_id.app_session_handle +#define hc_pa_app_api_ctx c_http_conn_id.parent_app_api_ctx +#define hc_hc_index connection.c_index http_version_t version; http_conn_state_t state; @@ -180,7 +221,7 @@ typedef struct http_tc_ http_conn_flags_t flags; http_udp_tunnel_mode_t udp_tunnel_mode; - http_req_t *req_pool; /* multiplexing => request per stream */ + void *opaque; /* version specific data */ } http_conn_t; typedef struct http_worker_ @@ -219,12 +260,27 @@ typedef struct http_main_ typedef struct http_engine_vft_ { - void (*app_tx_callback) (http_conn_t *hc, transport_send_params_t *sp); - void (*app_rx_evt_callback) (http_conn_t *hc); - void (*app_close_callback) (http_conn_t *hc); - void (*app_reset_callback) (http_conn_t *hc); + const char *name; + u32 (*hc_index_get_by_req_index) (u32 req_index, u32 thread_index); + transport_connection_t *(*req_get_connection) (u32 req_index, + u32 thread_index); + u8 *(*format_req) (u8 *s, va_list *args); + void (*app_tx_callback) (http_conn_t *hc, u32 req_index, + transport_send_params_t *sp); + void (*app_rx_evt_callback) (http_conn_t *hc, u32 req_index, + u32 thread_index); + void (*app_close_callback) (http_conn_t *hc, u32 req_index, + u32 thread_index); + void (*app_reset_callback) (http_conn_t *hc, u32 req_index, + u32 thread_index); + int (*transport_connected_callback) (http_conn_t *hc); void (*transport_rx_callback) (http_conn_t *hc); void (*transport_close_callback) (http_conn_t *hc); + void (*transport_reset_callback) (http_conn_t *hc); + void (*transport_conn_reschedule_callback) (http_conn_t *hc); + void (*conn_cleanup_callback) (http_conn_t *hc); + void (*enable_callback) (void); /* optional */ + uword (*unformat_cfg_callback) (unformat_input_t *input); /* optional */ } http_engine_vft_t; void http_register_engine (const http_engine_vft_t *vft, @@ -300,14 +356,14 @@ http_status_code_t http_sc_by_u16 (u16 status_code); /** * Read header list sent by app. * - * @param hc HTTP connection. + * @param req HTTP request. * @param msg HTTP msg sent by app. * * @return Pointer to the header list. * * @note For immediate processing, not for buffering. */ -u8 *http_get_app_header_list (http_conn_t *hc, http_msg_t *msg); +u8 *http_get_app_header_list (http_req_t *req, http_msg_t *msg); /** * Get pre-allocated TX buffer/vector. @@ -334,7 +390,7 @@ u8 *http_get_rx_buf (http_conn_t *hc); /** * Read request target path sent by app. * - * @param hc HTTP connection. + * @param req HTTP request. * @param msg HTTP msg sent by app. * * @return Pointer to the target path. @@ -354,69 +410,6 @@ u8 *http_get_app_target (http_req_t *req, http_msg_t *msg); void http_req_tx_buffer_init (http_req_t *req, http_msg_t *msg); /** - * Allocate new request within given HTTP connection. - * - * @param hc HTTP connection. - * - * @return Request index in per-connection pool. - */ -always_inline u32 -http_alloc_req (http_conn_t *hc) -{ - http_req_t *req; - pool_get_zero (hc->req_pool, req); - req->app_session_handle = SESSION_INVALID_HANDLE; - return (req - hc->req_pool); -} - -/** - * Get request in per-connection pool. - * - * @param hc HTTP connection. - * @param req_index Request index. - * - * @return Pointer to the request data. - */ -always_inline http_req_t * -http_get_req (http_conn_t *hc, u32 req_index) -{ - return pool_elt_at_index (hc->req_pool, req_index); -} - -/** - * Get request in per-connection pool if valid. - * - * @param hc HTTP connection. - * @param req_index Request index. - * - * @return Pointer to the request data or @c 0 if not valid. - */ -always_inline http_req_t * -http_get_req_if_valid (http_conn_t *hc, u32 req_index) -{ - if (pool_is_free_index (hc->req_pool, req_index)) - return 0; - return pool_elt_at_index (hc->req_pool, req_index); -} - -/** - * Free request in per-connection pool. - * - * @param hc HTTP connection. - * @param req Pointer to the request. - */ -always_inline void -http_req_free (http_conn_t *hc, http_req_t *req) -{ - vec_free (req->headers); - vec_free (req->target); - http_buffer_free (&req->tx_buf); - if (CLIB_DEBUG) - memset (req, 0xba, sizeof (*req)); - pool_put (hc->req_pool, req); -} - -/** * Change state of given HTTP request. * * @param req HTTP request. @@ -442,7 +435,7 @@ http_app_worker_rx_notify (http_req_t *req) session_t *as; app_worker_t *app_wrk; - as = session_get_from_handle (req->app_session_handle); + as = session_get_from_handle (req->hr_pa_session_handle); app_wrk = app_worker_get_if_valid (as->app_wrk_index); if (app_wrk) app_worker_rx_notify (app_wrk, as); @@ -459,7 +452,7 @@ always_inline transport_proto_t http_get_transport_proto (http_conn_t *hc) { return session_get_transport_proto ( - session_get_from_handle (hc->h_tc_session_handle)); + session_get_from_handle (hc->hc_tc_session_handle)); } /** @@ -474,7 +467,7 @@ http_get_app_msg (http_req_t *req, http_msg_t *msg) session_t *as; int rv; - as = session_get_from_handle (req->app_session_handle); + as = session_get_from_handle (req->hr_pa_session_handle); rv = svm_fifo_dequeue (as->tx_fifo, sizeof (*msg), (u8 *) msg); ASSERT (rv == sizeof (*msg)); } @@ -484,21 +477,21 @@ http_get_app_msg (http_req_t *req, http_msg_t *msg) always_inline void http_io_as_want_deq_ntf (http_req_t *req) { - session_t *as = session_get_from_handle (req->app_session_handle); + session_t *as = session_get_from_handle (req->hr_pa_session_handle); svm_fifo_add_want_deq_ntf (as->rx_fifo, SVM_FIFO_WANT_DEQ_NOTIF); } always_inline u32 http_io_as_max_write (http_req_t *req) { - session_t *as = session_get_from_handle (req->app_session_handle); + session_t *as = session_get_from_handle (req->hr_pa_session_handle); return svm_fifo_max_enqueue_prod (as->rx_fifo); } always_inline u32 http_io_as_max_read (http_req_t *req) { - session_t *as = session_get_from_handle (req->app_session_handle); + session_t *as = session_get_from_handle (req->hr_pa_session_handle); return svm_fifo_max_dequeue_cons (as->tx_fifo); } @@ -507,7 +500,7 @@ http_io_as_write_segs (http_req_t *req, const svm_fifo_seg_t segs[], u32 n_segs) { int n_written; - session_t *as = session_get_from_handle (req->app_session_handle); + session_t *as = session_get_from_handle (req->hr_pa_session_handle); n_written = svm_fifo_enqueue_segments (as->rx_fifo, segs, n_segs, 0); ASSERT (n_written > 0); return (u32) n_written; @@ -517,7 +510,7 @@ always_inline u32 http_io_as_read (http_req_t *req, u8 *buf, u32 len, u8 peek) { int n_read; - session_t *as = session_get_from_handle (req->app_session_handle); + session_t *as = session_get_from_handle (req->hr_pa_session_handle); if (peek) { @@ -537,7 +530,7 @@ http_io_as_read_segs (http_req_t *req, svm_fifo_seg_t *segs, u32 *n_segs, u32 max_bytes) { int n_read; - session_t *as = session_get_from_handle (req->app_session_handle); + session_t *as = session_get_from_handle (req->hr_pa_session_handle); n_read = svm_fifo_segments (as->tx_fifo, 0, segs, n_segs, max_bytes); ASSERT (n_read > 0); } @@ -545,7 +538,7 @@ http_io_as_read_segs (http_req_t *req, svm_fifo_seg_t *segs, u32 *n_segs, always_inline void http_io_as_drain (http_req_t *req, u32 len) { - session_t *as = session_get_from_handle (req->app_session_handle); + session_t *as = session_get_from_handle (req->hr_pa_session_handle); svm_fifo_dequeue_drop (as->tx_fifo, len); req->as_fifo_offset = 0; } @@ -553,7 +546,7 @@ http_io_as_drain (http_req_t *req, u32 len) always_inline void http_io_as_drain_all (http_req_t *req) { - session_t *as = session_get_from_handle (req->app_session_handle); + session_t *as = session_get_from_handle (req->hr_pa_session_handle); svm_fifo_dequeue_drop_all (as->tx_fifo); req->as_fifo_offset = 0; } @@ -563,14 +556,14 @@ http_io_as_drain_all (http_req_t *req) always_inline u32 http_io_ts_max_read (http_conn_t *hc) { - session_t *ts = session_get_from_handle (hc->h_tc_session_handle); + session_t *ts = session_get_from_handle (hc->hc_tc_session_handle); return svm_fifo_max_dequeue_cons (ts->rx_fifo); } always_inline u32 http_io_ts_max_write (http_conn_t *hc, transport_send_params_t *sp) { - session_t *ts = session_get_from_handle (hc->h_tc_session_handle); + session_t *ts = session_get_from_handle (hc->hc_tc_session_handle); return clib_min (svm_fifo_max_enqueue_prod (ts->tx_fifo), sp->max_burst_size); } @@ -579,7 +572,7 @@ always_inline u32 http_io_ts_read (http_conn_t *hc, u8 *buf, u32 len, u8 peek) { int n_read; - session_t *ts = session_get_from_handle (hc->h_tc_session_handle); + session_t *ts = session_get_from_handle (hc->hc_tc_session_handle); if (peek) { @@ -598,7 +591,7 @@ http_io_ts_read_segs (http_conn_t *hc, svm_fifo_seg_t *segs, u32 *n_segs, u32 max_bytes) { int n_read; - session_t *ts = session_get_from_handle (hc->h_tc_session_handle); + session_t *ts = session_get_from_handle (hc->hc_tc_session_handle); n_read = svm_fifo_segments (ts->rx_fifo, 0, segs, n_segs, max_bytes); ASSERT (n_read > 0); } @@ -606,21 +599,21 @@ http_io_ts_read_segs (http_conn_t *hc, svm_fifo_seg_t *segs, u32 *n_segs, always_inline void http_io_ts_drain (http_conn_t *hc, u32 len) { - session_t *ts = session_get_from_handle (hc->h_tc_session_handle); + session_t *ts = session_get_from_handle (hc->hc_tc_session_handle); svm_fifo_dequeue_drop (ts->rx_fifo, len); } always_inline void http_io_ts_drain_all (http_conn_t *hc) { - session_t *ts = session_get_from_handle (hc->h_tc_session_handle); + session_t *ts = session_get_from_handle (hc->hc_tc_session_handle); svm_fifo_dequeue_drop_all (ts->rx_fifo); } always_inline void http_io_ts_after_read (http_conn_t *hc, u8 clear_evt) { - session_t *ts = session_get_from_handle (hc->h_tc_session_handle); + session_t *ts = session_get_from_handle (hc->hc_tc_session_handle); if (clear_evt) { if (svm_fifo_is_empty_cons (ts->rx_fifo)) @@ -629,7 +622,7 @@ http_io_ts_after_read (http_conn_t *hc, u8 clear_evt) else { if (svm_fifo_max_dequeue_cons (ts->rx_fifo)) - session_program_rx_io_evt (hc->h_tc_session_handle); + session_program_rx_io_evt (hc->hc_tc_session_handle); } } @@ -638,7 +631,7 @@ http_io_ts_write (http_conn_t *hc, u8 *data, u32 len, transport_send_params_t *sp) { int n_written; - session_t *ts = session_get_from_handle (hc->h_tc_session_handle); + session_t *ts = session_get_from_handle (hc->hc_tc_session_handle); n_written = svm_fifo_enqueue (ts->tx_fifo, len, data); ASSERT (n_written == len); @@ -655,7 +648,7 @@ http_io_ts_write_segs (http_conn_t *hc, const svm_fifo_seg_t segs[], u32 n_segs, transport_send_params_t *sp) { int n_written; - session_t *ts = session_get_from_handle (hc->h_tc_session_handle); + session_t *ts = session_get_from_handle (hc->hc_tc_session_handle); n_written = svm_fifo_enqueue_segments (ts->tx_fifo, segs, n_segs, 0); ASSERT (n_written > 0); sp->bytes_dequeued += n_written; @@ -667,7 +660,7 @@ always_inline void http_io_ts_after_write (http_conn_t *hc, transport_send_params_t *sp, u8 flush, u8 written) { - session_t *ts = session_get_from_handle (hc->h_tc_session_handle); + session_t *ts = session_get_from_handle (hc->hc_tc_session_handle); if (!flush) { @@ -690,4 +683,97 @@ http_io_ts_after_write (http_conn_t *hc, transport_send_params_t *sp, u8 flush, } } +always_inline int +http_conn_accept_request (http_conn_t *hc, http_req_t *req) +{ + session_t *as, *asl; + app_worker_t *app_wrk; + int rv; + + HTTP_DBG (1, "hc [%u]%x req %x", hc->hc_hc_index, hc->c_thread_index, + req->hr_req_index); + + /* allocate app session and initialize */ + as = session_alloc (hc->c_thread_index); + HTTP_DBG (1, "allocated session 0x%lx", session_handle (as)); + req->c_s_index = as->session_index; + as->app_wrk_index = hc->hc_pa_wrk_index; + as->connection_index = req->hr_req_handle; + as->session_state = SESSION_STATE_ACCEPTING; + asl = listen_session_get_from_handle (hc->hc_pa_session_handle); + as->session_type = asl->session_type; + as->listener_handle = hc->hc_pa_session_handle; + + /* init session fifos and notify app */ + if ((rv = app_worker_init_accepted (as))) + { + HTTP_DBG (1, "failed to allocate fifos"); + req->hr_pa_session_handle = SESSION_INVALID_HANDLE; + session_free (as); + hc->flags |= HTTP_CONN_F_NO_APP_SESSION; + return rv; + } + + req->hr_pa_session_handle = session_handle (as); + req->hr_pa_wrk_index = as->app_wrk_index; + + app_wrk = app_worker_get (as->app_wrk_index); + + if ((rv = app_worker_accept_notify (app_wrk, as))) + { + HTTP_DBG (1, "app accept returned"); + req->hr_pa_session_handle = SESSION_INVALID_HANDLE; + session_free (as); + hc->flags |= HTTP_CONN_F_NO_APP_SESSION; + return rv; + } + + return 0; +} + +always_inline int +http_conn_established (http_conn_t *hc, http_req_t *req) +{ + session_t *as; + app_worker_t *app_wrk; + session_t *ts; + int rv; + + /* allocate app session and initialize */ + as = session_alloc (hc->c_thread_index); + HTTP_DBG (1, "allocated session 0x%lx", session_handle (as)); + req->c_s_index = as->session_index; + as->app_wrk_index = hc->hc_pa_wrk_index; + as->connection_index = req->hr_req_handle; + as->session_state = SESSION_STATE_READY; + as->opaque = hc->hc_pa_app_api_ctx; + ts = session_get_from_handle (hc->hc_tc_session_handle); + as->session_type = session_type_from_proto_and_ip ( + TRANSPORT_PROTO_HTTP, session_type_is_ip4 (ts->session_type)); + + /* init session fifos and notify app */ + app_wrk = app_worker_get_if_valid (hc->hc_pa_wrk_index); + if (!app_wrk) + { + HTTP_DBG (1, "no app worker"); + hc->flags |= HTTP_CONN_F_NO_APP_SESSION; + return -1; + } + + if ((rv = app_worker_init_connected (app_wrk, as))) + { + HTTP_DBG (1, "failed to allocate fifos"); + session_free (as); + hc->flags |= HTTP_CONN_F_NO_APP_SESSION; + return rv; + } + + app_worker_connect_notify (app_wrk, as, 0, hc->hc_pa_app_api_ctx); + + req->hr_pa_session_handle = session_handle (as); + req->hr_pa_wrk_index = as->app_wrk_index; + + return 0; +} + #endif /* SRC_PLUGINS_HTTP_HTTP_PRIVATE_H_ */ diff --git a/src/plugins/http/http_timer.h b/src/plugins/http/http_timer.h index 50f634c5397..5ce42032f20 100644 --- a/src/plugins/http/http_timer.h +++ b/src/plugins/http/http_timer.h @@ -45,8 +45,8 @@ http_conn_timer_start (http_conn_t *hc) u32 hs_handle; ASSERT (hc->timer_handle == HTTP_TIMER_HANDLE_INVALID); - ASSERT (hc->h_hc_index <= 0x00FFFFFF); - hs_handle = hc->c_thread_index << 24 | hc->h_hc_index; + ASSERT (hc->hc_hc_index <= 0x00FFFFFF); + hs_handle = hc->c_thread_index << 24 | hc->hc_hc_index; clib_spinlock_lock (&twc->tw_lock); hc->timer_handle = @@ -80,8 +80,8 @@ http_conn_timer_update (http_conn_t *hc) tw_timer_update_2t_1w_2048sl (&twc->tw, hc->timer_handle, hc->timeout); else { - ASSERT (hc->h_hc_index <= 0x00FFFFFF); - hs_handle = hc->c_thread_index << 24 | hc->h_hc_index; + ASSERT (hc->hc_hc_index <= 0x00FFFFFF); + hs_handle = hc->c_thread_index << 24 | hc->hc_hc_index; hc->timer_handle = tw_timer_start_2t_1w_2048sl (&twc->tw, hs_handle, 0, hc->timeout); } |