aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2025-03-07 08:02:42 -0500
committerFlorin Coras <florin.coras@gmail.com>2025-03-24 17:03:48 +0000
commit8e50ec8dcadc33f057a621efbfdc948fd414784e (patch)
treee595359420cf0e92c742fe882fb20f82ebee6c35 /src
parent7aebf804fe0050d4a48aab591b55f026e8dcc4c4 (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.c382
-rw-r--r--src/plugins/http/http1.c279
-rw-r--r--src/plugins/http/http_private.h308
-rw-r--r--src/plugins/http/http_timer.h8
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);
}