LCOV - code coverage report
Current view: top level - plugins/hs_apps - http_tps.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 9 377 2.4 %
Date: 2023-07-05 22:20:52 Functions: 7 33 21.2 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2022 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <vnet/session/application.h>
      17             : #include <vnet/session/application_interface.h>
      18             : #include <vnet/session/session.h>
      19             : #include <http/http.h>
      20             : 
      21             : typedef struct
      22             : {
      23             :   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
      24             :   u32 session_index;
      25             :   u32 thread_index;
      26             :   u64 data_len;
      27             :   u64 data_offset;
      28             :   u32 vpp_session_index;
      29             :   union
      30             :   {
      31             :     /** threshold after which connection is closed */
      32             :     f64 close_threshold;
      33             :     /** rate at which accepted sessions are marked for random close */
      34             :     u32 close_rate;
      35             :   };
      36             :   u8 *uri;
      37             : } hts_session_t;
      38             : 
      39             : typedef struct hts_listen_cfg_
      40             : {
      41             :   u8 *uri;
      42             :   u32 vrf;
      43             :   f64 rnd_close;
      44             :   u8 is_del;
      45             : } hts_listen_cfg_t;
      46             : 
      47             : typedef struct hs_main_
      48             : {
      49             :   hts_session_t **sessions;
      50             :   u32 app_index;
      51             : 
      52             :   u32 ckpair_index;
      53             :   u8 *test_data;
      54             : 
      55             :   /** Hash table of listener uris to handles */
      56             :   uword *uri_to_handle;
      57             : 
      58             :   /*
      59             :    * Configs
      60             :    */
      61             :   u8 *uri;
      62             :   u32 fifo_size;
      63             :   u64 segment_size;
      64             :   u8 debug_level;
      65             :   u8 no_zc;
      66             :   u8 *default_uri;
      67             :   u32 seed;
      68             : } hts_main_t;
      69             : 
      70             : static hts_main_t hts_main;
      71             : 
      72             : static hts_session_t *
      73           0 : hts_session_alloc (u32 thread_index)
      74             : {
      75           0 :   hts_main_t *htm = &hts_main;
      76             :   hts_session_t *hs;
      77             : 
      78           0 :   pool_get_zero (htm->sessions[thread_index], hs);
      79           0 :   hs->session_index = hs - htm->sessions[thread_index];
      80           0 :   hs->thread_index = thread_index;
      81             : 
      82           0 :   return hs;
      83             : }
      84             : 
      85             : static hts_session_t *
      86           0 : hts_session_get (u32 thread_index, u32 hts_index)
      87             : {
      88           0 :   hts_main_t *htm = &hts_main;
      89             : 
      90           0 :   if (pool_is_free_index (htm->sessions[thread_index], hts_index))
      91           0 :     return 0;
      92             : 
      93           0 :   return pool_elt_at_index (htm->sessions[thread_index], hts_index);
      94             : }
      95             : 
      96             : static void
      97           0 : hts_session_free (hts_session_t *hs)
      98             : {
      99           0 :   hts_main_t *htm = &hts_main;
     100           0 :   u32 thread = hs->thread_index;
     101             : 
     102           0 :   if (htm->debug_level > 0)
     103           0 :     clib_warning ("Freeing session %u", hs->session_index);
     104             : 
     105             :   if (CLIB_DEBUG)
     106           0 :     clib_memset (hs, 0xfa, sizeof (*hs));
     107             : 
     108           0 :   pool_put (htm->sessions[thread], hs);
     109           0 : }
     110             : 
     111             : static void
     112           0 : hts_disconnect_transport (hts_session_t *hs)
     113             : {
     114           0 :   vnet_disconnect_args_t _a = { 0 }, *a = &_a;
     115           0 :   hts_main_t *htm = &hts_main;
     116             :   session_t *ts;
     117             : 
     118           0 :   if (htm->debug_level > 0)
     119           0 :     clib_warning ("Actively closing session %u", hs->session_index);
     120             : 
     121           0 :   ts = session_get (hs->vpp_session_index, hs->thread_index);
     122           0 :   a->handle = session_handle (ts);
     123           0 :   a->app_index = htm->app_index;
     124           0 :   vnet_disconnect_session (a);
     125           0 : }
     126             : 
     127             : static void
     128           0 : hts_session_tx_zc (hts_session_t *hs, session_t *ts)
     129             : {
     130             :   u32 to_send, space;
     131             :   u64 max_send;
     132             :   int rv;
     133             : 
     134           0 :   rv = svm_fifo_fill_chunk_list (ts->tx_fifo);
     135           0 :   if (rv < 0)
     136             :     {
     137           0 :       svm_fifo_add_want_deq_ntf (ts->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
     138           0 :       return;
     139             :     }
     140             : 
     141           0 :   max_send = hs->data_len - hs->data_offset;
     142           0 :   space = svm_fifo_max_enqueue (ts->tx_fifo);
     143           0 :   ASSERT (space != 0);
     144           0 :   to_send = clib_min (space, max_send);
     145             : 
     146           0 :   svm_fifo_enqueue_nocopy (ts->tx_fifo, to_send);
     147             : 
     148           0 :   hs->data_offset += to_send;
     149             : 
     150           0 :   if (to_send < max_send)
     151           0 :     svm_fifo_add_want_deq_ntf (ts->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
     152             : 
     153           0 :   if (svm_fifo_set_event (ts->tx_fifo))
     154           0 :     session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
     155             : }
     156             : 
     157             : static void
     158           0 : hts_session_tx_no_zc (hts_session_t *hs, session_t *ts)
     159             : {
     160             :   u32 n_segs, buf_offset, buf_left;
     161           0 :   u64 max_send = 32 << 10, left;
     162           0 :   hts_main_t *htm = &hts_main;
     163             :   svm_fifo_seg_t seg[2];
     164             :   int sent;
     165             : 
     166           0 :   left = hs->data_len - hs->data_offset;
     167           0 :   max_send = clib_min (left, max_send);
     168           0 :   buf_offset = hs->data_offset % vec_len (htm->test_data);
     169           0 :   buf_left = vec_len (htm->test_data) - buf_offset;
     170             : 
     171           0 :   if (buf_left < max_send)
     172             :     {
     173           0 :       seg[0].data = htm->test_data + buf_offset;
     174           0 :       seg[0].len = buf_left;
     175           0 :       seg[1].data = htm->test_data;
     176           0 :       seg[1].len = max_send - buf_left;
     177           0 :       n_segs = 2;
     178             :     }
     179             :   else
     180             :     {
     181           0 :       seg[0].data = htm->test_data + buf_offset;
     182           0 :       seg[0].len = max_send;
     183           0 :       n_segs = 1;
     184             :     }
     185             : 
     186           0 :   sent = svm_fifo_enqueue_segments (ts->tx_fifo, seg, n_segs,
     187             :                                     1 /* allow partial */);
     188             : 
     189           0 :   if (sent <= 0)
     190             :     {
     191           0 :       svm_fifo_add_want_deq_ntf (ts->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
     192           0 :       return;
     193             :     }
     194             : 
     195           0 :   hs->data_offset += sent;
     196             : 
     197           0 :   if (sent < left)
     198           0 :     svm_fifo_add_want_deq_ntf (ts->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
     199             : 
     200           0 :   if (svm_fifo_set_event (ts->tx_fifo))
     201           0 :     session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
     202             : }
     203             : 
     204             : static inline void
     205           0 : hts_session_tx (hts_session_t *hs, session_t *ts)
     206             : {
     207           0 :   hts_main_t *htm = &hts_main;
     208             : 
     209           0 :   if (!htm->no_zc)
     210           0 :     hts_session_tx_zc (hs, ts);
     211             :   else
     212           0 :     hts_session_tx_no_zc (hs, ts);
     213             : 
     214           0 :   if (hs->close_threshold > 0)
     215             :     {
     216           0 :       if ((f64) hs->data_offset / hs->data_len > hs->close_threshold)
     217           0 :         hts_disconnect_transport (hs);
     218             :     }
     219           0 : }
     220             : 
     221             : static void
     222           0 : hts_start_send_data (hts_session_t *hs, http_status_code_t status)
     223             : {
     224             :   http_msg_t msg;
     225             :   session_t *ts;
     226             :   int rv;
     227             : 
     228           0 :   msg.type = HTTP_MSG_REPLY;
     229           0 :   msg.code = status;
     230           0 :   msg.content_type = HTTP_CONTENT_APP_OCTET_STREAM;
     231           0 :   msg.data.type = HTTP_MSG_DATA_INLINE;
     232           0 :   msg.data.len = hs->data_len;
     233             : 
     234           0 :   ts = session_get (hs->vpp_session_index, hs->thread_index);
     235           0 :   rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (msg), (u8 *) &msg);
     236           0 :   ASSERT (rv == sizeof (msg));
     237             : 
     238           0 :   if (!msg.data.len)
     239             :     {
     240           0 :       if (svm_fifo_set_event (ts->tx_fifo))
     241           0 :         session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
     242           0 :       return;
     243             :     }
     244             : 
     245           0 :   hts_session_tx (hs, ts);
     246             : }
     247             : 
     248             : static int
     249           0 : try_test_file (hts_session_t *hs, u8 *request)
     250             : {
     251           0 :   char *test_str = "test_file";
     252           0 :   hts_main_t *htm = &hts_main;
     253             :   unformat_input_t input;
     254             :   uword file_size;
     255           0 :   int rc = 0;
     256             : 
     257           0 :   if (memcmp (request, test_str, clib_strnlen (test_str, 9)))
     258           0 :     return -1;
     259             : 
     260           0 :   unformat_init_vector (&input, vec_dup (request));
     261           0 :   if (!unformat (&input, "test_file_%U", unformat_memory_size, &file_size))
     262             :     {
     263           0 :       rc = -1;
     264           0 :       goto done;
     265             :     }
     266             : 
     267           0 :   if (unformat_check_input (&input) != UNFORMAT_END_OF_INPUT)
     268             :     {
     269           0 :       rc = -1;
     270           0 :       goto done;
     271             :     }
     272             : 
     273           0 :   if (htm->debug_level)
     274           0 :     clib_warning ("Requested file size %U", format_memory_size, file_size);
     275             : 
     276           0 :   hs->data_len = file_size;
     277           0 :   hs->data_offset = 0;
     278             : 
     279           0 :   if (hs->close_threshold > 0)
     280             :     {
     281             :       /* Disconnect if the header is already enough to fill the quota */
     282           0 :       if ((f64) 30 / hs->data_len > hs->close_threshold)
     283             :         {
     284           0 :           hts_disconnect_transport (hs);
     285           0 :           goto done;
     286             :         }
     287             :     }
     288             : 
     289           0 :   hts_start_send_data (hs, HTTP_STATUS_OK);
     290             : 
     291           0 : done:
     292           0 :   unformat_free (&input);
     293             : 
     294           0 :   return rc;
     295             : }
     296             : 
     297             : static int
     298           0 : hts_ts_rx_callback (session_t *ts)
     299             : {
     300             :   hts_session_t *hs;
     301           0 :   u8 *request = 0;
     302             :   http_msg_t msg;
     303             :   int rv;
     304             : 
     305           0 :   hs = hts_session_get (ts->thread_index, ts->opaque);
     306             : 
     307             :   /* Read the http message header */
     308           0 :   rv = svm_fifo_dequeue (ts->rx_fifo, sizeof (msg), (u8 *) &msg);
     309           0 :   ASSERT (rv == sizeof (msg));
     310             : 
     311           0 :   if (msg.type != HTTP_MSG_REQUEST || msg.method_type != HTTP_REQ_GET)
     312             :     {
     313           0 :       hts_start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED);
     314           0 :       goto done;
     315             :     }
     316             : 
     317           0 :   if (!msg.data.len)
     318             :     {
     319           0 :       hts_start_send_data (hs, HTTP_STATUS_BAD_REQUEST);
     320           0 :       goto done;
     321             :     }
     322             : 
     323           0 :   vec_validate (request, msg.data.len - 1);
     324           0 :   rv = svm_fifo_dequeue (ts->rx_fifo, msg.data.len, request);
     325             : 
     326           0 :   if (try_test_file (hs, request))
     327           0 :     hts_start_send_data (hs, HTTP_STATUS_NOT_FOUND);
     328             : 
     329           0 : done:
     330             : 
     331           0 :   return 0;
     332             : }
     333             : 
     334             : static int
     335           0 : hs_ts_tx_callback (session_t *ts)
     336             : {
     337             :   hts_session_t *hs;
     338             : 
     339           0 :   hs = hts_session_get (ts->thread_index, ts->opaque);
     340           0 :   if (!hs)
     341           0 :     return 0;
     342             : 
     343           0 :   hts_session_tx (hs, ts);
     344             : 
     345           0 :   return 0;
     346             : }
     347             : 
     348             : static int
     349           0 : hts_ts_accept_callback (session_t *ts)
     350             : {
     351           0 :   hts_main_t *htm = &hts_main;
     352             :   hts_session_t *hs, *lhs;
     353             :   session_t *ls;
     354             : 
     355           0 :   hs = hts_session_alloc (ts->thread_index);
     356           0 :   hs->vpp_session_index = ts->session_index;
     357             : 
     358           0 :   ts->opaque = hs->session_index;
     359           0 :   ts->session_state = SESSION_STATE_READY;
     360             : 
     361             :   /* Check if listener configured for random closes */
     362           0 :   ls = listen_session_get_from_handle (ts->listener_handle);
     363           0 :   lhs = hts_session_get (0, ls->opaque);
     364             : 
     365           0 :   if (lhs->close_rate)
     366             :     {
     367             :       /* overload listener's data_offset as session counter */
     368           0 :       u32 cnt = __atomic_add_fetch (&lhs->data_offset, 1, __ATOMIC_RELEASE);
     369           0 :       if ((cnt % lhs->close_rate) == 0)
     370           0 :         hs->close_threshold = random_f64 (&htm->seed);
     371             :     }
     372             : 
     373           0 :   if (htm->debug_level > 0)
     374           0 :     clib_warning ("Accepted session %u close threshold %.2f", ts->opaque,
     375             :                   hs->close_threshold);
     376             : 
     377           0 :   return 0;
     378             : }
     379             : 
     380             : static int
     381           0 : hts_ts_connected_callback (u32 app_index, u32 api_context, session_t *s,
     382             :                            session_error_t err)
     383             : {
     384           0 :   clib_warning ("called...");
     385           0 :   return -1;
     386             : }
     387             : 
     388             : static void
     389           0 : hts_ts_disconnect_callback (session_t *ts)
     390             : {
     391           0 :   hts_main_t *htm = &hts_main;
     392           0 :   vnet_disconnect_args_t _a = { 0 }, *a = &_a;
     393             : 
     394           0 :   if (htm->debug_level > 0)
     395           0 :     clib_warning ("Transport closing session %u", ts->opaque);
     396             : 
     397           0 :   a->handle = session_handle (ts);
     398           0 :   a->app_index = htm->app_index;
     399           0 :   vnet_disconnect_session (a);
     400           0 : }
     401             : 
     402             : static void
     403           0 : hts_ts_reset_callback (session_t *ts)
     404             : {
     405           0 :   hts_main_t *htm = &hts_main;
     406           0 :   vnet_disconnect_args_t _a = { 0 }, *a = &_a;
     407             : 
     408           0 :   if (htm->debug_level > 0)
     409           0 :     clib_warning ("Transport reset session %u", ts->opaque);
     410             : 
     411           0 :   a->handle = session_handle (ts);
     412           0 :   a->app_index = htm->app_index;
     413           0 :   vnet_disconnect_session (a);
     414           0 : }
     415             : 
     416             : static void
     417           0 : hts_ts_cleanup_callback (session_t *s, session_cleanup_ntf_t ntf)
     418             : {
     419             :   hts_session_t *hs;
     420             : 
     421           0 :   if (ntf == SESSION_CLEANUP_TRANSPORT)
     422           0 :     return;
     423             : 
     424           0 :   hs = hts_session_get (s->thread_index, s->opaque);
     425           0 :   if (!hs)
     426           0 :     return;
     427             : 
     428           0 :   hts_session_free (hs);
     429             : }
     430             : 
     431             : static int
     432           0 : hts_add_segment_callback (u32 client_index, u64 segment_handle)
     433             : {
     434           0 :   return 0;
     435             : }
     436             : 
     437             : static int
     438           0 : hts_del_segment_callback (u32 client_index, u64 segment_handle)
     439             : {
     440           0 :   return 0;
     441             : }
     442             : 
     443             : static session_cb_vft_t hs_session_cb_vft = {
     444             :   .session_accept_callback = hts_ts_accept_callback,
     445             :   .session_disconnect_callback = hts_ts_disconnect_callback,
     446             :   .session_connected_callback = hts_ts_connected_callback,
     447             :   .add_segment_callback = hts_add_segment_callback,
     448             :   .del_segment_callback = hts_del_segment_callback,
     449             :   .builtin_app_rx_callback = hts_ts_rx_callback,
     450             :   .builtin_app_tx_callback = hs_ts_tx_callback,
     451             :   .session_reset_callback = hts_ts_reset_callback,
     452             :   .session_cleanup_callback = hts_ts_cleanup_callback,
     453             : };
     454             : 
     455             : static int
     456           0 : hts_attach (hts_main_t *hm)
     457             : {
     458           0 :   vnet_app_add_cert_key_pair_args_t _ck_pair, *ck_pair = &_ck_pair;
     459             :   u64 options[APP_OPTIONS_N_OPTIONS];
     460           0 :   vnet_app_attach_args_t _a, *a = &_a;
     461             : 
     462           0 :   clib_memset (a, 0, sizeof (*a));
     463           0 :   clib_memset (options, 0, sizeof (options));
     464             : 
     465           0 :   a->api_client_index = ~0;
     466           0 :   a->name = format (0, "http_tps");
     467           0 :   a->session_cb_vft = &hs_session_cb_vft;
     468           0 :   a->options = options;
     469           0 :   a->options[APP_OPTIONS_SEGMENT_SIZE] = hm->segment_size;
     470           0 :   a->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = hm->segment_size;
     471           0 :   a->options[APP_OPTIONS_RX_FIFO_SIZE] = hm->fifo_size;
     472           0 :   a->options[APP_OPTIONS_TX_FIFO_SIZE] = hm->fifo_size;
     473           0 :   a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
     474             : 
     475           0 :   if (vnet_application_attach (a))
     476             :     {
     477           0 :       vec_free (a->name);
     478           0 :       clib_warning ("failed to attach server");
     479           0 :       return -1;
     480             :     }
     481           0 :   vec_free (a->name);
     482           0 :   hm->app_index = a->app_index;
     483             : 
     484           0 :   clib_memset (ck_pair, 0, sizeof (*ck_pair));
     485           0 :   ck_pair->cert = (u8 *) test_srv_crt_rsa;
     486           0 :   ck_pair->key = (u8 *) test_srv_key_rsa;
     487           0 :   ck_pair->cert_len = test_srv_crt_rsa_len;
     488           0 :   ck_pair->key_len = test_srv_key_rsa_len;
     489           0 :   vnet_app_add_cert_key_pair (ck_pair);
     490           0 :   hm->ckpair_index = ck_pair->index;
     491             : 
     492           0 :   return 0;
     493             : }
     494             : 
     495             : static int
     496           0 : hts_transport_needs_crypto (transport_proto_t proto)
     497             : {
     498           0 :   return proto == TRANSPORT_PROTO_TLS || proto == TRANSPORT_PROTO_DTLS ||
     499             :          proto == TRANSPORT_PROTO_QUIC;
     500             : }
     501             : 
     502             : static int
     503           0 : hts_start_listen (hts_main_t *htm, session_endpoint_cfg_t *sep, u8 *uri,
     504             :                   f64 rnd_close)
     505             : {
     506           0 :   vnet_listen_args_t _a, *a = &_a;
     507             :   u8 need_crypto;
     508             :   hts_session_t *hls;
     509             :   session_t *ls;
     510           0 :   u32 thread_index = 0;
     511             :   int rv;
     512             : 
     513           0 :   clib_memset (a, 0, sizeof (*a));
     514           0 :   a->app_index = htm->app_index;
     515             : 
     516           0 :   need_crypto = hts_transport_needs_crypto (sep->transport_proto);
     517             : 
     518           0 :   sep->transport_proto = TRANSPORT_PROTO_HTTP;
     519           0 :   clib_memcpy (&a->sep_ext, sep, sizeof (*sep));
     520             : 
     521           0 :   if (need_crypto)
     522             :     {
     523           0 :       session_endpoint_alloc_ext_cfg (&a->sep_ext,
     524             :                                       TRANSPORT_ENDPT_EXT_CFG_CRYPTO);
     525           0 :       a->sep_ext.ext_cfg->crypto.ckpair_index = htm->ckpair_index;
     526             :     }
     527             : 
     528           0 :   rv = vnet_listen (a);
     529             : 
     530           0 :   if (need_crypto)
     531           0 :     clib_mem_free (a->sep_ext.ext_cfg);
     532             : 
     533           0 :   if (rv)
     534           0 :     return rv;
     535             : 
     536           0 :   hls = hts_session_alloc (thread_index);
     537           0 :   hls->uri = vec_dup (uri);
     538           0 :   hls->close_rate = (f64) 1 / rnd_close;
     539           0 :   ls = listen_session_get_from_handle (a->handle);
     540           0 :   hls->vpp_session_index = ls->session_index;
     541           0 :   hash_set_mem (htm->uri_to_handle, hls->uri, hls->session_index);
     542             : 
     543             :   /* opaque holds index of hls, which is used in `hts_ts_accept_callback`
     544             :    * to get back the pointer to hls */
     545           0 :   ls->opaque = hls - htm->sessions[thread_index];
     546             : 
     547           0 :   return 0;
     548             : }
     549             : 
     550             : static int
     551           0 : hts_stop_listen (hts_main_t *htm, u32 hls_index)
     552             : {
     553             :   hts_session_t *hls;
     554             :   session_t *ls;
     555             : 
     556           0 :   hls = hts_session_get (0, hls_index);
     557           0 :   ls = listen_session_get (hls->vpp_session_index);
     558             : 
     559           0 :   vnet_unlisten_args_t ua = {
     560           0 :     .handle = listen_session_get_handle (ls),
     561           0 :     .app_index = htm->app_index,
     562             :     .wrk_map_index = 0 /* default wrk */
     563             :   };
     564             : 
     565           0 :   hash_unset_mem (htm->uri_to_handle, hls->uri);
     566             : 
     567           0 :   if (vnet_unlisten (&ua))
     568           0 :     return -1;
     569             : 
     570           0 :   vec_free (hls->uri);
     571           0 :   hts_session_free (hls);
     572             : 
     573           0 :   return 0;
     574             : }
     575             : 
     576             : static clib_error_t *
     577           0 : hts_listen (hts_main_t *htm, hts_listen_cfg_t *lcfg)
     578             : {
     579           0 :   session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
     580           0 :   clib_error_t *error = 0;
     581             :   u8 *uri, *uri_key;
     582             :   uword *p;
     583             :   int rv;
     584             : 
     585           0 :   uri = lcfg->uri ? lcfg->uri : htm->default_uri;
     586           0 :   uri_key = format (0, "vrf%u-%s", lcfg->vrf, uri);
     587           0 :   p = hash_get_mem (htm->uri_to_handle, uri_key);
     588             : 
     589           0 :   if (lcfg->is_del)
     590             :     {
     591           0 :       if (!p)
     592           0 :         error = clib_error_return (0, "not listening on %v", uri);
     593           0 :       else if (hts_stop_listen (htm, p[0]))
     594           0 :         error = clib_error_return (0, "failed to unlisten");
     595           0 :       goto done;
     596             :     }
     597             : 
     598           0 :   if (p)
     599             :     {
     600           0 :       error = clib_error_return (0, "already listening %v", uri);
     601           0 :       goto done;
     602             :     }
     603             : 
     604           0 :   if (parse_uri ((char *) uri, &sep))
     605             :     {
     606           0 :       error = clib_error_return (0, "failed to parse uri %v", uri);
     607           0 :       goto done;
     608             :     }
     609             : 
     610           0 :   if (lcfg->vrf)
     611             :     {
     612             :       fib_protocol_t fp;
     613             :       u32 fib_index;
     614             : 
     615           0 :       fp = sep.is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
     616           0 :       fib_index = fib_table_find (fp, lcfg->vrf);
     617           0 :       if (fib_index == ~0)
     618             :         {
     619           0 :           error = clib_error_return (0, "no such vrf %u", lcfg->vrf);
     620           0 :           goto done;
     621             :         }
     622           0 :       sep.fib_index = fib_index;
     623             :     }
     624             : 
     625           0 :   if ((rv = hts_start_listen (htm, &sep, uri_key, lcfg->rnd_close)))
     626             :     {
     627           0 :       error = clib_error_return (0, "failed to listen on %v: %U", uri,
     628             :                                  format_session_error, rv);
     629             :     }
     630             : 
     631           0 : done:
     632             : 
     633           0 :   vec_free (uri_key);
     634           0 :   return error;
     635             : }
     636             : 
     637             : static int
     638           0 : hts_create (vlib_main_t *vm)
     639             : {
     640           0 :   vlib_thread_main_t *vtm = vlib_get_thread_main ();
     641           0 :   hts_main_t *htm = &hts_main;
     642             :   u32 num_threads;
     643             : 
     644           0 :   num_threads = 1 /* main thread */ + vtm->n_threads;
     645           0 :   vec_validate (htm->sessions, num_threads - 1);
     646             : 
     647           0 :   if (htm->no_zc)
     648           0 :     vec_validate (htm->test_data, (64 << 10) - 1);
     649             : 
     650           0 :   if (hts_attach (htm))
     651             :     {
     652           0 :       clib_warning ("failed to attach server");
     653           0 :       return -1;
     654             :     }
     655             : 
     656           0 :   htm->default_uri = format (0, "tcp://0.0.0.0/80%c", 0);
     657           0 :   htm->uri_to_handle = hash_create_vec (0, sizeof (u8), sizeof (uword));
     658             : 
     659           0 :   return 0;
     660             : }
     661             : 
     662             : static clib_error_t *
     663           0 : hts_create_command_fn (vlib_main_t *vm, unformat_input_t *input,
     664             :                        vlib_cli_command_t *cmd)
     665             : {
     666           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     667           0 :   hts_main_t *htm = &hts_main;
     668           0 :   hts_listen_cfg_t lcfg = {};
     669           0 :   clib_error_t *error = 0;
     670             :   u64 mem_size;
     671             : 
     672             :   /* Get a line of input. */
     673           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     674           0 :     goto start_server;
     675             : 
     676           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     677             :     {
     678           0 :       if (unformat (line_input, "private-segment-size %U",
     679             :                     unformat_memory_size, &mem_size))
     680           0 :         htm->segment_size = mem_size;
     681           0 :       else if (unformat (line_input, "fifo-size %U", unformat_memory_size,
     682             :                          &mem_size))
     683           0 :         htm->fifo_size = mem_size;
     684           0 :       else if (unformat (line_input, "no-zc"))
     685           0 :         htm->no_zc = 1;
     686           0 :       else if (unformat (line_input, "debug"))
     687           0 :         htm->debug_level = 1;
     688           0 :       else if (unformat (line_input, "vrf %u", &lcfg.vrf))
     689             :         ;
     690           0 :       else if (unformat (line_input, "uri %s", &lcfg.uri))
     691             :         ;
     692           0 :       else if (unformat (line_input, "rnd-close %f", &lcfg.rnd_close))
     693             :         {
     694           0 :           if (lcfg.rnd_close > 1.0)
     695             :             {
     696           0 :               error = clib_error_return (0, "invalid rnd close value %f",
     697             :                                          lcfg.rnd_close);
     698           0 :               break;
     699             :             }
     700             :         }
     701           0 :       else if (unformat (line_input, "del"))
     702           0 :         lcfg.is_del = 1;
     703             :       else
     704             :         {
     705           0 :           error = clib_error_return (0, "unknown input `%U'",
     706             :                                      format_unformat_error, line_input);
     707           0 :           break;
     708             :         }
     709             :     }
     710             : 
     711           0 :   unformat_free (line_input);
     712             : 
     713           0 :   if (error)
     714           0 :     goto done;
     715             : 
     716           0 : start_server:
     717             : 
     718           0 :   if (htm->app_index == (u32) ~0)
     719             :     {
     720           0 :       vnet_session_enable_disable (vm, 1 /* is_enable */);
     721             : 
     722           0 :       if (hts_create (vm))
     723             :         {
     724           0 :           error = clib_error_return (0, "http tps create failed");
     725           0 :           goto done;
     726             :         }
     727             :     }
     728             : 
     729           0 :   error = hts_listen (htm, &lcfg);
     730             : 
     731           0 : done:
     732             : 
     733           0 :   vec_free (lcfg.uri);
     734           0 :   return error;
     735             : }
     736             : 
     737      203447 : VLIB_CLI_COMMAND (http_tps_command, static) = {
     738             :   .path = "http tps",
     739             :   .short_help = "http tps [uri <uri>] [fifo-size <nbytes>] "
     740             :                 "[segment-size <nMG>] [prealloc-fifos <n>] [debug] [no-zc] "
     741             :                 "[del]",
     742             :   .function = hts_create_command_fn,
     743             : };
     744             : 
     745             : static clib_error_t *
     746           0 : hts_show_command_fn (vlib_main_t *vm, unformat_input_t *input,
     747             :                      vlib_cli_command_t *cmd)
     748             : {
     749           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     750           0 :   hts_main_t *htm = &hts_main;
     751           0 :   clib_error_t *error = 0;
     752           0 :   u8 do_listeners = 0;
     753             :   hts_session_t **sessions;
     754           0 :   u32 n_listeners = 0, n_sessions = 0;
     755             : 
     756           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     757           0 :     goto no_input;
     758             : 
     759           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     760             :     {
     761           0 :       if (unformat (line_input, "listeners"))
     762           0 :         do_listeners = 1;
     763             :       else
     764             :         {
     765           0 :           error = clib_error_return (0, "unknown input `%U'",
     766             :                                      format_unformat_error, line_input);
     767           0 :           break;
     768             :         }
     769             :     }
     770             : 
     771           0 :   if (error)
     772           0 :     return error;
     773             : 
     774           0 : no_input:
     775             : 
     776           0 :   if (htm->app_index == ~0)
     777             :     {
     778           0 :       vlib_cli_output (vm, "http tps not enabled");
     779           0 :       goto done;
     780             :     }
     781             : 
     782           0 :   if (do_listeners)
     783             :     {
     784             :       uword handle;
     785           0 :       u8 *s = 0, *uri;
     786             : 
     787             :       /* clang-format off */
     788           0 :       hash_foreach (uri, handle, htm->uri_to_handle, ({
     789             :         s = format (s, "%-30v%lx\n", uri, handle);
     790             :       }));
     791             :       /* clang-format on */
     792             : 
     793           0 :       if (s)
     794             :         {
     795           0 :           vlib_cli_output (vm, "%-29s%s", "URI", "Index");
     796           0 :           vlib_cli_output (vm, "%v", s);
     797           0 :           vec_free (s);
     798             :         }
     799           0 :       goto done;
     800             :     }
     801             : 
     802           0 :   n_listeners = hash_elts (htm->uri_to_handle);
     803           0 :   vec_foreach (sessions, htm->sessions)
     804           0 :     n_sessions += pool_elts (*sessions);
     805             : 
     806           0 :   vlib_cli_output (vm, " app index: %u\n listeners: %u\n sesions: %u",
     807             :                    htm->app_index, n_listeners, n_sessions - n_listeners);
     808             : 
     809           0 : done:
     810           0 :   return 0;
     811             : }
     812             : 
     813      203447 : VLIB_CLI_COMMAND (show_http_tps_command, static) = {
     814             :   .path = "show http tps",
     815             :   .short_help = "http tps [listeners]",
     816             :   .function = hts_show_command_fn,
     817             : };
     818             : 
     819             : static clib_error_t *
     820         559 : hs_main_init (vlib_main_t *vm)
     821             : {
     822         559 :   hts_main_t *htm = &hts_main;
     823             : 
     824         559 :   htm->app_index = ~0;
     825         559 :   htm->segment_size = 128 << 20;
     826         559 :   htm->fifo_size = 64 << 10;
     827             : 
     828         559 :   return 0;
     829             : }
     830             : 
     831        2799 : VLIB_INIT_FUNCTION (hs_main_init);
     832             : 
     833             : /*
     834             :  * fd.io coding-style-patch-verification: ON
     835             :  *
     836             :  * Local Variables:
     837             :  * eval: (c-set-style "gnu")
     838             :  * End:
     839             :  */

Generated by: LCOV version 1.14