session: add support for memfd segments
[vpp.git] / src / vnet / tcp / builtin_http_server.c
index 07c8a4d..5510f8a 100644 (file)
@@ -31,8 +31,8 @@ typedef struct
 
 typedef struct
 {
-  u8 *rx_buf;
-  unix_shared_memory_queue_t **vpp_queue;
+  u8 **rx_buf;
+  svm_queue_t **vpp_queue;
   u64 byte_index;
 
   uword *handler_by_get_request;
@@ -40,7 +40,7 @@ typedef struct
   u32 *free_http_cli_process_node_indices;
 
   /* Sever's event queue */
-  unix_shared_memory_queue_t *vl_input_queue;
+  svm_queue_t *vl_input_queue;
 
   /* API client handle */
   u32 my_client_index;
@@ -49,6 +49,10 @@ typedef struct
 
   /* process node index for evnt scheduling */
   u32 node_index;
+
+  u32 prealloc_fifos;
+  u32 private_segment_size;
+  u32 fifo_size;
   vlib_main_t *vlib_main;
 } http_server_main_t;
 
@@ -102,6 +106,13 @@ static const char
 
 static const char *html_footer = "</pre></body></html>\r\n";
 
+static const char
+  *html_header_static = "<html><head><title>static reply</title></head>"
+  "<link rel=\"icon\" href=\"data:,\"><body><pre>hello</pre></body>"
+  "</html>\r\n";
+
+static u8 *static_http;
+
 static void
 http_cli_output (uword arg, u8 * buffer, uword buffer_bytes)
 {
@@ -119,7 +130,7 @@ http_cli_output (uword arg, u8 * buffer, uword buffer_bytes)
 }
 
 void
-send_data (builtin_http_server_args * args, u8 * data)
+send_data (stream_session_t * s, u8 * data)
 {
   session_fifo_event_t evt;
   u32 offset, bytes_to_send;
@@ -127,10 +138,7 @@ send_data (builtin_http_server_args * args, u8 * data)
   http_server_main_t *hsm = &http_server_main;
   vlib_main_t *vm = hsm->vlib_main;
   f64 last_sent_timer = vlib_time_now (vm);
-  stream_session_t *s;
 
-  s = session_get_from_handle (args->session_handle);
-  ASSERT (s);
   bytes_to_send = vec_len (data);
   offset = 0;
 
@@ -167,9 +175,8 @@ send_data (builtin_http_server_args * args, u8 * data)
              evt.fifo = s->server_tx_fifo;
              evt.event_type = FIFO_EVENT_APP_TX;
 
-             unix_shared_memory_queue_add (hsm->vpp_queue[s->thread_index],
-                                           (u8 *) & evt,
-                                           0 /* do wait for mutex */ );
+             svm_queue_add (hsm->vpp_queue[s->thread_index],
+                            (u8 *) & evt, 0 /* do wait for mutex */ );
            }
          delay = 10e-3;
        }
@@ -177,12 +184,12 @@ send_data (builtin_http_server_args * args, u8 * data)
 }
 
 static void
-send_error (builtin_http_server_args * args, char *str)
+send_error (stream_session_t * s, char *str)
 {
   u8 *data;
 
   data = format (0, http_error_template, str);
-  send_data (args, data);
+  send_data (s, data);
   vec_free (data);
 }
 
@@ -194,17 +201,20 @@ http_cli_process (vlib_main_t * vm,
   u8 *request = 0, *reply = 0;
   builtin_http_server_args **save_args;
   builtin_http_server_args *args;
+  stream_session_t *s;
   unformat_input_t input;
   int i;
   u8 *http = 0, *html = 0;
 
   save_args = vlib_node_get_runtime_data (hsm->vlib_main, rt->node_index);
   args = *save_args;
+  s = session_get_from_handle (args->session_handle);
+  ASSERT (s);
 
   request = (u8 *) (void *) (args->data);
   if (vec_len (request) < 7)
     {
-      send_error (args, "400 Bad Request");
+      send_error (s, "400 Bad Request");
       goto out;
     }
 
@@ -216,7 +226,7 @@ http_cli_process (vlib_main_t * vm,
        goto found;
     }
 bad_request:
-  send_error (args, "400 Bad Request");
+  send_error (s, "400 Bad Request");
   goto out;
 
 found:
@@ -257,7 +267,7 @@ found:
   http = format (0, http_response, vec_len (html), html);
 
   /* Send it */
-  send_data (args, http);
+  send_data (s, http);
 
 out:
   /* Cleanup */
@@ -320,31 +330,43 @@ alloc_http_process_callback (void *cb_args)
 }
 
 static int
-http_server_rx_callback (stream_session_t * s)
+session_rx_request (stream_session_t * s)
 {
-  u32 max_dequeue;
-  int actual_transfer;
   http_server_main_t *hsm = &http_server_main;
   svm_fifo_t *rx_fifo;
-  builtin_http_server_args *args;
+  u32 max_dequeue;
+  int actual_transfer;
 
   rx_fifo = s->server_rx_fifo;
   max_dequeue = svm_fifo_max_dequeue (rx_fifo);
   svm_fifo_unset_event (rx_fifo);
   if (PREDICT_FALSE (max_dequeue == 0))
-    return 0;
+    return -1;
 
-  vec_validate (hsm->rx_buf, max_dequeue - 1);
-  _vec_len (hsm->rx_buf) = max_dequeue;
+  vec_validate (hsm->rx_buf[s->thread_index], max_dequeue - 1);
+  _vec_len (hsm->rx_buf[s->thread_index]) = max_dequeue;
 
   actual_transfer = svm_fifo_dequeue_nowait (rx_fifo, max_dequeue,
-                                            hsm->rx_buf);
+                                            hsm->rx_buf[s->thread_index]);
   ASSERT (actual_transfer > 0);
-  _vec_len (hsm->rx_buf) = actual_transfer;
+  _vec_len (hsm->rx_buf[s->thread_index]) = actual_transfer;
+  return 0;
+}
+
+static int
+http_server_rx_callback (stream_session_t * s)
+{
+  http_server_main_t *hsm = &http_server_main;
+  builtin_http_server_args *args;
+  int rv;
+
+  rv = session_rx_request (s);
+  if (rv)
+    return rv;
 
   /* send the command to a new/recycled vlib process */
   args = clib_mem_alloc (sizeof (*args));
-  args->data = vec_dup (hsm->rx_buf);
+  args->data = vec_dup (hsm->rx_buf[s->thread_index]);
   args->session_handle = session_handle (s);
 
   /* Send an RPC request via the thread-0 input node */
@@ -354,7 +376,7 @@ http_server_rx_callback (stream_session_t * s)
       evt.rpc_args.fp = alloc_http_process_callback;
       evt.rpc_args.arg = args;
       evt.event_type = FIFO_EVENT_RPC;
-      unix_shared_memory_queue_add
+      svm_queue_add
        (session_manager_get_vpp_event_queue (0 /* main thread */ ),
         (u8 *) & evt, 0 /* do wait for mutex */ );
     }
@@ -363,6 +385,47 @@ http_server_rx_callback (stream_session_t * s)
   return 0;
 }
 
+static int
+http_server_rx_callback_static (stream_session_t * s)
+{
+  http_server_main_t *hsm = &http_server_main;
+  u8 *request = 0;
+  int i;
+  int rv;
+
+  rv = session_rx_request (s);
+  if (rv)
+    return rv;
+
+  request = hsm->rx_buf[s->thread_index];
+  if (vec_len (request) < 7)
+    {
+      send_error (s, "400 Bad Request");
+      goto out;
+    }
+
+  for (i = 0; i < vec_len (request) - 4; i++)
+    {
+      if (request[i] == 'G' &&
+         request[i + 1] == 'E' &&
+         request[i + 2] == 'T' && request[i + 3] == ' ')
+       goto found;
+    }
+  send_error (s, "400 Bad Request");
+  goto out;
+
+found:
+
+  /* Send it */
+  send_data (s, static_http);
+
+out:
+  /* Cleanup */
+  vec_free (request);
+  hsm->rx_buf[s->thread_index] = request;
+  return 0;
+}
+
 static int
 builtin_session_accept_callback (stream_session_t * s)
 {
@@ -403,8 +466,7 @@ builtin_session_connected_callback (u32 app_index, u32 api_context,
 }
 
 static int
-builtin_add_segment_callback (u32 client_index,
-                             const u8 * seg_name, u32 seg_size)
+builtin_add_segment_callback (u32 client_index, const ssvm_private_t * sp)
 {
   clib_warning ("called...");
   return -1;
@@ -438,7 +500,7 @@ create_api_loopback (vlib_main_t * vm)
   shmem_hdr = am->shmem_hdr;
   hsm->vl_input_queue = shmem_hdr->vl_input_queue;
   hsm->my_client_index =
-    vl_api_memclnt_create_internal ("tcp_test_client", hsm->vl_input_queue);
+    vl_api_memclnt_create_internal ("test_http_server", hsm->vl_input_queue);
   return 0;
 }
 
@@ -446,23 +508,26 @@ static int
 server_attach ()
 {
   http_server_main_t *hsm = &http_server_main;
-  u8 segment_name[128];
-  u64 options[SESSION_OPTIONS_N_OPTIONS];
+  u64 options[APP_OPTIONS_N_OPTIONS];
   vnet_app_attach_args_t _a, *a = &_a;
+  u32 segment_size = 128 << 20;
 
   memset (a, 0, sizeof (*a));
   memset (options, 0, sizeof (options));
 
+  if (hsm->private_segment_size)
+    segment_size = hsm->private_segment_size;
+
   a->api_client_index = hsm->my_client_index;
   a->session_cb_vft = &builtin_session_cb_vft;
   a->options = options;
-  a->options[SESSION_OPTIONS_SEGMENT_SIZE] = 128 << 20;
-  a->options[SESSION_OPTIONS_RX_FIFO_SIZE] = 8 << 10;
-  a->options[SESSION_OPTIONS_TX_FIFO_SIZE] = 32 << 10;
+  a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
+  a->options[APP_OPTIONS_RX_FIFO_SIZE] =
+    hsm->fifo_size ? hsm->fifo_size : 8 << 10;
+  a->options[APP_OPTIONS_TX_FIFO_SIZE] =
+    hsm->fifo_size ? hsm->fifo_size : 32 << 10;
   a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
-  a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = 16;
-  a->segment_name = segment_name;
-  a->segment_name_length = ARRAY_LEN (segment_name);
+  a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = hsm->prealloc_fifos;
 
   if (vnet_application_attach (a))
     {
@@ -516,12 +581,48 @@ server_create_command_fn (vlib_main_t * vm,
                          unformat_input_t * input, vlib_cli_command_t * cmd)
 {
   http_server_main_t *hsm = &http_server_main;
-  int rv;
-
+  int rv, is_static = 0;
+  u64 seg_size;
+  u8 *html;
+
+  hsm->prealloc_fifos = 0;
+  hsm->private_segment_size = 0;
+  hsm->fifo_size = 0;
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "static"))
+       is_static = 1;
+      else if (unformat (input, "prealloc-fifos %d", &hsm->prealloc_fifos))
+       ;
+      else if (unformat (input, "private-segment-size %U",
+                        unformat_memory_size, &seg_size))
+       {
+         if (seg_size >= 0x100000000ULL)
+           {
+             vlib_cli_output (vm, "private segment size %llu, too large",
+                              seg_size);
+             return 0;
+           }
+         hsm->private_segment_size = seg_size;
+       }
+      else if (unformat (input, "fifo-size %d", &hsm->fifo_size))
+       hsm->fifo_size <<= 10;
+      else
+       return clib_error_return (0, "unknown input `%U'",
+                                 format_unformat_error, input);
+    }
   if (hsm->my_client_index != (u32) ~ 0)
     return clib_error_return (0, "test http server is already running");
 
   vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
+
+  if (is_static)
+    {
+      builtin_session_cb_vft.builtin_server_rx_callback =
+       http_server_rx_callback_static;
+      html = format (0, html_header_static);
+      static_http = format (0, http_response, vec_len (html), html);
+    }
   rv = server_create (vm);
   switch (rv)
     {
@@ -546,9 +647,13 @@ static clib_error_t *
 builtin_http_server_main_init (vlib_main_t * vm)
 {
   http_server_main_t *hsm = &http_server_main;
+  vlib_thread_main_t *vtm = vlib_get_thread_main ();
+  u32 num_threads;
+
   hsm->my_client_index = ~0;
   hsm->vlib_main = vm;
-
+  num_threads = 1 /* main thread */  + vtm->n_threads;
+  vec_validate (hsm->rx_buf, num_threads - 1);
   return 0;
 }