From 1d88fb97bef7dbe998830ea1eb2f8519c6cc9e97 Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Mon, 24 Jan 2022 12:47:50 -0800 Subject: http: generalize buffer implementation And add support for passing of pointers Type: improvement Signed-off-by: Florin Coras Change-Id: Ida3e5ae4ff7842366ae92a5f33c5e761355951a6 --- src/plugins/hs_apps/http_server.c | 3 +- src/plugins/http/CMakeLists.txt | 1 + src/plugins/http/http.c | 73 +++---------- src/plugins/http/http.h | 20 ++-- src/plugins/http/http_buffer.c | 217 ++++++++++++++++++++++++++++++++++++++ src/plugins/http/http_buffer.h | 82 ++++++++++++++ 6 files changed, 323 insertions(+), 73 deletions(-) create mode 100644 src/plugins/http/http_buffer.c create mode 100644 src/plugins/http/http_buffer.h (limited to 'src') diff --git a/src/plugins/hs_apps/http_server.c b/src/plugins/hs_apps/http_server.c index 7a4a5194022..3083937ec74 100644 --- a/src/plugins/hs_apps/http_server.c +++ b/src/plugins/hs_apps/http_server.c @@ -159,7 +159,8 @@ start_send_data (http_session_t *hs, http_status_code_t status) msg.type = HTTP_MSG_REPLY; msg.code = status; - msg.data.content_type = HTTP_CONTENT_TEXT_HTML; + msg.content_type = HTTP_CONTENT_TEXT_HTML; + msg.data.type = HTTP_MSG_DATA_INLINE; msg.data.len = vec_len (hs->tx_buf); ts = session_get (hs->vpp_session_index, hs->thread_index); diff --git a/src/plugins/http/CMakeLists.txt b/src/plugins/http/CMakeLists.txt index 9f5ce778739..d9cd84a3955 100644 --- a/src/plugins/http/CMakeLists.txt +++ b/src/plugins/http/CMakeLists.txt @@ -14,5 +14,6 @@ add_vpp_plugin(http SOURCES http.c + http_buffer.c http_timer.c ) diff --git a/src/plugins/http/http.c b/src/plugins/http/http.c index 705af9a9ef5..683b2a4d135 100644 --- a/src/plugins/http/http.c +++ b/src/plugins/http/http.c @@ -31,6 +31,11 @@ const char *http_content_type_str[] = { #undef _ }; +const http_buffer_type_t msg_to_buf_type[] = { + [HTTP_MSG_DATA_INLINE] = HTTP_BUFFER_FIFO, + [HTTP_MSG_DATA_PTR] = HTTP_BUFFER_PTR, +}; + static inline http_worker_t * http_worker_get (u32 thread_index) { @@ -96,59 +101,6 @@ http_disconnect_transport (http_conn_t *hc) clib_warning ("disconnect returned"); } -static void -http_buffer_init (http_buffer_t *hb, svm_fifo_t *f, u32 data_len) -{ - hb->len = data_len; - hb->offset = 0; - hb->cur_seg = 0; - hb->src = f; - hb->segs = 0; -} - -static void -http_buffer_free (http_buffer_t *hb) -{ - hb->src = 0; - vec_free (hb->segs); -} - -svm_fifo_seg_t * -http_buffer_get_segs (http_buffer_t *hb, u32 max_len, u32 *n_segs) -{ - u32 _n_segs = 5; - int len; - - max_len = clib_max (hb->len - hb->offset, max_len); - - vec_validate (hb->segs, _n_segs); - - len = svm_fifo_segments (hb->src, 0, hb->segs, &_n_segs, max_len); - if (len < 0) - return 0; - - *n_segs = _n_segs; - - HTTP_DBG (1, "available to send %u n_segs %u", len, *n_segs); - - return hb->segs; -} - -void -http_buffer_drain (http_buffer_t *hb, u32 len) -{ - hb->offset += len; - svm_fifo_dequeue_drop (hb->src, len); - HTTP_DBG (1, "drained %u len %u offset %u", len, hb->len, hb->offset); -} - -static inline u8 -http_buffer_is_drained (http_buffer_t *hb) -{ - ASSERT (hb->offset <= hb->len); - return (hb->offset == hb->len); -} - static void http_conn_timeout_cb (void *hc_handlep) { @@ -437,9 +389,9 @@ state_wait_method (http_conn_t *hc, transport_send_params_t *sp) msg.type = HTTP_MSG_REQUEST; msg.method_type = hc->method; - msg.data.content_type = HTTP_CONTENT_TEXT_HTML; + msg.content_type = HTTP_CONTENT_TEXT_HTML; + msg.data.type = HTTP_MSG_DATA_INLINE; msg.data.len = len; - msg.data.offset = 0; svm_fifo_seg_t segs[2] = { { (u8 *) &msg, sizeof (msg) }, { buf, len } }; @@ -491,7 +443,7 @@ state_wait_app (http_conn_t *hc, transport_send_params_t *sp) rv = svm_fifo_dequeue (as->tx_fifo, sizeof (msg), (u8 *) &msg); ASSERT (rv == sizeof (msg)); - if (msg.type != HTTP_MSG_REPLY) + if (msg.type != HTTP_MSG_REPLY || msg.data.type > HTTP_MSG_DATA_PTR) { clib_warning ("unexpected msg type from app %u", msg.type); ec = HTTP_STATUS_INTERNAL_ERROR; @@ -504,7 +456,8 @@ state_wait_app (http_conn_t *hc, transport_send_params_t *sp) goto error; } - http_buffer_init (&hc->tx_buf, as->tx_fifo, msg.data.len); + http_buffer_init (&hc->tx_buf, msg_to_buf_type[msg.data.type], as->tx_fifo, + msg.data.len); /* * Add headers. For now: @@ -520,7 +473,7 @@ state_wait_app (http_conn_t *hc, transport_send_params_t *sp) /* Expires */ format_clib_timebase_time, now + 600.0, /* Content type */ - http_content_type_str[msg.data.content_type], + http_content_type_str[msg.content_type], /* Length */ msg.data.len); @@ -565,10 +518,8 @@ state_send_more_data (http_conn_t *hc, transport_send_params_t *sp) if (sent > 0) { - http_buffer_drain (hb, sent); - /* Ask scheduler to notify app of deq event if needed */ - sp->max_burst_size = sent; + sp->max_burst_size = http_buffer_drain (hb, sent); } else { diff --git a/src/plugins/http/http.h b/src/plugins/http/http.h index 209fc3236df..a75e6bcdacb 100644 --- a/src/plugins/http/http.h +++ b/src/plugins/http/http.h @@ -23,6 +23,7 @@ #include #include +#include #define HTTP_DEBUG 0 @@ -105,11 +106,16 @@ typedef enum http_status_code_ HTTP_N_STATUS } http_status_code_t; +typedef enum http_msg_data_type_ +{ + HTTP_MSG_DATA_INLINE, + HTTP_MSG_DATA_PTR +} http_msg_data_type_t; + typedef struct http_msg_data_ { - http_content_type_t content_type; + http_msg_data_type_t type; u32 len; - u32 offset; u8 data[0]; } http_msg_data_t; @@ -121,18 +127,10 @@ typedef struct http_msg_ http_req_method_t method_type; http_status_code_t code; }; + http_content_type_t content_type; http_msg_data_t data; } http_msg_t; -typedef struct http_buffer_ -{ - svm_fifo_t *src; - svm_fifo_seg_t *segs; - u32 len; - u32 cur_seg; - u32 offset; -} http_buffer_t; - typedef struct http_tc_ { union diff --git a/src/plugins/http/http_buffer.c b/src/plugins/http/http_buffer.c new file mode 100644 index 00000000000..5b4f5fc0300 --- /dev/null +++ b/src/plugins/http/http_buffer.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +static http_buffer_vft_t buf_vfts[HTTP_BUFFER_PTR + 1]; + +#define HTTP_BUFFER_REGISTER_VFT(type, vft) \ + static void __attribute__ ((constructor)) http_buf_init_##type (void) \ + { \ + buf_vfts[type] = vft; \ + } + +typedef struct http_buffer_fifo_ +{ + svm_fifo_t *src; + svm_fifo_seg_t *segs; + u32 len; + u32 offset; +} http_buffer_fifo_t; + +STATIC_ASSERT (sizeof (http_buffer_fifo_t) <= HTTP_BUFFER_DATA_SZ, "buf data"); + +static void +buf_fifo_init (http_buffer_t *hb, void *data, u32 len) +{ + svm_fifo_t *f = (svm_fifo_t *) data; + http_buffer_fifo_t *bf; + + bf = (http_buffer_fifo_t *) &hb->data; + + bf->len = len; + bf->offset = 0; + bf->src = f; + bf->segs = 0; +} + +static void +buf_fifo_free (http_buffer_t *hb) +{ + http_buffer_fifo_t *bf = (http_buffer_fifo_t *) &hb->data; + + bf->src = 0; + vec_free (bf->segs); +} + +static svm_fifo_seg_t * +buf_fifo_get_segs (http_buffer_t *hb, u32 max_len, u32 *n_segs) +{ + http_buffer_fifo_t *bf = (http_buffer_fifo_t *) &hb->data; + + u32 _n_segs = 5; + int len; + + max_len = clib_max (bf->len - bf->offset, max_len); + + vec_validate (bf->segs, _n_segs); + + len = svm_fifo_segments (bf->src, 0, bf->segs, &_n_segs, max_len); + if (len < 0) + return 0; + + *n_segs = _n_segs; + + HTTP_DBG (1, "available to send %u n_segs %u", len, *n_segs); + + return bf->segs; +} + +static int +buf_fifo_drain (http_buffer_t *hb, u32 len) +{ + http_buffer_fifo_t *bf = (http_buffer_fifo_t *) &hb->data; + + bf->offset += len; + svm_fifo_dequeue_drop (bf->src, len); + HTTP_DBG (1, "drained %u len %u offset %u", len, bf->len, bf->offset); + + return len; +} + +static u8 +buf_fifo_is_drained (http_buffer_t *hb) +{ + http_buffer_fifo_t *bf = (http_buffer_fifo_t *) &hb->data; + + ASSERT (bf->offset <= bf->len); + return (bf->offset == bf->len); +} + +const static http_buffer_vft_t buf_fifo_vft = { + .init = buf_fifo_init, + .free = buf_fifo_free, + .get_segs = buf_fifo_get_segs, + .drain = buf_fifo_drain, + .is_drained = buf_fifo_is_drained, +}; + +HTTP_BUFFER_REGISTER_VFT (HTTP_BUFFER_FIFO, buf_fifo_vft); + +typedef struct http_buffer_ptr_ +{ + svm_fifo_seg_t *segs; + svm_fifo_t *f; +} http_buffer_ptr_t; + +STATIC_ASSERT (sizeof (http_buffer_ptr_t) <= HTTP_BUFFER_DATA_SZ, "buf data"); + +static void +buf_ptr_init (http_buffer_t *hb, void *data, u32 len) +{ + svm_fifo_t *f = (svm_fifo_t *) data; + http_buffer_ptr_t *bf; + uword ptr; + int rv; + + bf = (http_buffer_ptr_t *) &hb->data; + + /* Peek the pointer, do not drain the fifo until done with transfer */ + rv = svm_fifo_peek (f, 0, sizeof (ptr), (u8 *) &ptr); + ASSERT (rv == sizeof (ptr)); + + bf->f = f; + bf->segs = 0; + vec_validate (bf->segs, 1); + + bf->segs[0].data = uword_to_pointer (ptr, u8 *); + bf->segs[0].len = len; + + bf->segs[1] = bf->segs[0]; +} + +static void +buf_ptr_free (http_buffer_t *hb) +{ + http_buffer_ptr_t *bf = (http_buffer_ptr_t *) &hb->data; + + bf->f = 0; + vec_free (bf->segs); +} + +static svm_fifo_seg_t * +buf_ptr_get_segs (http_buffer_t *hb, u32 max_len, u32 *n_segs) +{ + http_buffer_ptr_t *bf = (http_buffer_ptr_t *) &hb->data; + + *n_segs = 1; + + return &bf->segs[1]; +} + +static int +buf_ptr_drain (http_buffer_t *hb, u32 len) +{ + http_buffer_ptr_t *bf = (http_buffer_ptr_t *) &hb->data; + + bf->segs[1].data += len; + bf->segs[1].len -= len; + + HTTP_DBG (1, "drained %u left %u", len, bf->segs[1].len); + + if (!bf->segs[1].len) + { + svm_fifo_dequeue_drop (bf->f, sizeof (uword)); + return sizeof (uword); + } + + return 0; +} + +static u8 +buf_ptr_is_drained (http_buffer_t *hb) +{ + http_buffer_ptr_t *bf = (http_buffer_ptr_t *) &hb->data; + + ASSERT (bf->segs[1].len <= bf->segs[0].len); + return (bf->segs[1].len == 0); +} + +const static http_buffer_vft_t buf_ptr_vft = { + .init = buf_ptr_init, + .free = buf_ptr_free, + .get_segs = buf_ptr_get_segs, + .drain = buf_ptr_drain, + .is_drained = buf_ptr_is_drained, +}; + +HTTP_BUFFER_REGISTER_VFT (HTTP_BUFFER_PTR, buf_ptr_vft); + +void +http_buffer_init (http_buffer_t *hb, http_buffer_type_t type, svm_fifo_t *f, + u32 data_len) +{ + hb->vft = &buf_vfts[type]; + hb->vft->init (hb, f, data_len); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/http/http_buffer.h b/src/plugins/http/http_buffer.h new file mode 100644 index 00000000000..5c7569b9e3c --- /dev/null +++ b/src/plugins/http/http_buffer.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SRC_PLUGINS_HTTP_HTTP_BUFFER_H_ +#define SRC_PLUGINS_HTTP_HTTP_BUFFER_H_ + +#include + +#define HTTP_BUFFER_DATA_SZ 24 + +typedef enum http_buffer_type_ +{ + HTTP_BUFFER_FIFO, + HTTP_BUFFER_PTR, +} http_buffer_type_t; + +typedef struct http_buffer_vft_ http_buffer_vft_t; + +typedef struct http_buffer_ +{ + http_buffer_vft_t *vft; + u8 data[HTTP_BUFFER_DATA_SZ]; +} http_buffer_t; + +struct http_buffer_vft_ +{ + void (*init) (http_buffer_t *, void *data, u32 len); + void (*free) (http_buffer_t *); + svm_fifo_seg_t *(*get_segs) (http_buffer_t *, u32 max_len, u32 *n_segs); + int (*drain) (http_buffer_t *, u32 len); + u8 (*is_drained) (http_buffer_t *); +}; + +void http_buffer_init (http_buffer_t *hb, http_buffer_type_t type, + svm_fifo_t *f, u32 data_len); + +static inline void +http_buffer_free (http_buffer_t *hb) +{ + if (hb->vft) + hb->vft->free (hb); +} + +static inline svm_fifo_seg_t * +http_buffer_get_segs (http_buffer_t *hb, u32 max_len, u32 *n_segs) +{ + return hb->vft->get_segs (hb, max_len, n_segs); +} + +static inline int +http_buffer_drain (http_buffer_t *hb, u32 len) +{ + return hb->vft->drain (hb, len); +} + +static inline u8 +http_buffer_is_drained (http_buffer_t *hb) +{ + return hb->vft->is_drained (hb); +} + +#endif /* SRC_PLUGINS_HTTP_HTTP_BUFFER_H_ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg