Line data Source code
1 : /*
2 : * Copyright (c) 2017-2019 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 : u32 hs_index;
24 : u32 thread_index;
25 : u64 node_index;
26 : u8 *buf;
27 : } hcs_cli_args_t;
28 :
29 : typedef struct
30 : {
31 : CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
32 : u32 session_index;
33 : u32 thread_index;
34 : u8 *tx_buf;
35 : u32 tx_offset;
36 : u32 vpp_session_index;
37 : } hcs_session_t;
38 :
39 : typedef struct
40 : {
41 : hcs_session_t **sessions;
42 : u32 *free_http_cli_process_node_indices;
43 : u32 app_index;
44 :
45 : /* Cert key pair for tls */
46 : u32 ckpair_index;
47 :
48 : u32 prealloc_fifos;
49 : u32 private_segment_size;
50 : u32 fifo_size;
51 : u8 *uri;
52 : vlib_main_t *vlib_main;
53 : } hcs_main_t;
54 :
55 : static hcs_main_t hcs_main;
56 :
57 : static hcs_session_t *
58 0 : hcs_session_alloc (u32 thread_index)
59 : {
60 0 : hcs_main_t *hcm = &hcs_main;
61 : hcs_session_t *hs;
62 0 : pool_get (hcm->sessions[thread_index], hs);
63 0 : memset (hs, 0, sizeof (*hs));
64 0 : hs->session_index = hs - hcm->sessions[thread_index];
65 0 : hs->thread_index = thread_index;
66 0 : return hs;
67 : }
68 :
69 : static hcs_session_t *
70 0 : hcs_session_get (u32 thread_index, u32 hs_index)
71 : {
72 0 : hcs_main_t *hcm = &hcs_main;
73 0 : if (pool_is_free_index (hcm->sessions[thread_index], hs_index))
74 0 : return 0;
75 0 : return pool_elt_at_index (hcm->sessions[thread_index], hs_index);
76 : }
77 :
78 : static void
79 0 : hcs_session_free (hcs_session_t *hs)
80 : {
81 0 : hcs_main_t *hcm = &hcs_main;
82 0 : u32 thread = hs->thread_index;
83 : if (CLIB_DEBUG)
84 0 : memset (hs, 0xfa, sizeof (*hs));
85 0 : pool_put (hcm->sessions[thread], hs);
86 0 : }
87 :
88 : static void
89 0 : hcs_cli_process_free (hcs_cli_args_t *args)
90 : {
91 0 : vlib_main_t *vm = vlib_get_first_main ();
92 0 : hcs_main_t *hcm = &hcs_main;
93 : hcs_cli_args_t **save_args;
94 : vlib_node_runtime_t *rt;
95 : vlib_node_t *n;
96 : u32 node_index;
97 :
98 0 : node_index = args->node_index;
99 0 : ASSERT (node_index != 0);
100 :
101 0 : n = vlib_get_node (vm, node_index);
102 0 : rt = vlib_node_get_runtime (vm, n->index);
103 0 : save_args = vlib_node_get_runtime_data (vm, n->index);
104 :
105 : /* Reset process session pointer */
106 0 : clib_mem_free (*save_args);
107 0 : *save_args = 0;
108 :
109 : /* Turn off the process node */
110 0 : vlib_node_set_state (vm, rt->node_index, VLIB_NODE_STATE_DISABLED);
111 :
112 : /* add node index to the freelist */
113 0 : vec_add1 (hcm->free_http_cli_process_node_indices, node_index);
114 0 : }
115 :
116 : /* Header, including incantation to suppress favicon.ico requests */
117 : static const char *html_header_template =
118 : "<html><head><title>%v</title></head>"
119 : "<link rel=\"icon\" href=\"data:,\">"
120 : "<body><pre>";
121 :
122 : static const char *html_footer =
123 : "</pre></body></html>\r\n";
124 :
125 : static void
126 0 : hcs_cli_output (uword arg, u8 *buffer, uword buffer_bytes)
127 : {
128 0 : u8 **output_vecp = (u8 **) arg;
129 : u8 *output_vec;
130 : u32 offset;
131 :
132 0 : output_vec = *output_vecp;
133 :
134 0 : offset = vec_len (output_vec);
135 0 : vec_validate (output_vec, offset + buffer_bytes - 1);
136 0 : clib_memcpy_fast (output_vec + offset, buffer, buffer_bytes);
137 :
138 0 : *output_vecp = output_vec;
139 0 : }
140 :
141 : static void
142 0 : start_send_data (hcs_session_t *hs, http_status_code_t status)
143 : {
144 : http_msg_t msg;
145 : session_t *ts;
146 : int rv;
147 :
148 0 : msg.type = HTTP_MSG_REPLY;
149 0 : msg.code = status;
150 0 : msg.content_type = HTTP_CONTENT_TEXT_HTML;
151 0 : msg.data.type = HTTP_MSG_DATA_INLINE;
152 0 : msg.data.len = vec_len (hs->tx_buf);
153 :
154 0 : ts = session_get (hs->vpp_session_index, hs->thread_index);
155 0 : rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (msg), (u8 *) &msg);
156 0 : ASSERT (rv == sizeof (msg));
157 :
158 0 : if (!msg.data.len)
159 0 : goto done;
160 :
161 0 : rv = svm_fifo_enqueue (ts->tx_fifo, vec_len (hs->tx_buf), hs->tx_buf);
162 :
163 0 : if (rv != vec_len (hs->tx_buf))
164 : {
165 0 : hs->tx_offset = rv;
166 0 : svm_fifo_add_want_deq_ntf (ts->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
167 : }
168 : else
169 : {
170 0 : vec_free (hs->tx_buf);
171 : }
172 :
173 0 : done:
174 :
175 0 : if (svm_fifo_set_event (ts->tx_fifo))
176 0 : session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
177 0 : }
178 :
179 : static void
180 0 : send_data_to_http (void *rpc_args)
181 : {
182 0 : hcs_cli_args_t *args = (hcs_cli_args_t *) rpc_args;
183 : hcs_session_t *hs;
184 :
185 0 : hs = hcs_session_get (args->thread_index, args->hs_index);
186 0 : if (!hs)
187 : {
188 0 : vec_free (args->buf);
189 0 : goto cleanup;
190 : }
191 :
192 0 : hs->tx_buf = args->buf;
193 0 : start_send_data (hs, HTTP_STATUS_OK);
194 :
195 0 : cleanup:
196 :
197 0 : clib_mem_free (rpc_args);
198 0 : }
199 :
200 : static uword
201 0 : hcs_cli_process (vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
202 : {
203 0 : u8 *request = 0, *reply = 0, *html = 0;
204 : hcs_cli_args_t *args, *rpc_args;
205 0 : hcs_main_t *hcm = &hcs_main;
206 : hcs_cli_args_t **save_args;
207 : unformat_input_t input;
208 : int i;
209 :
210 0 : save_args = vlib_node_get_runtime_data (hcm->vlib_main, rt->node_index);
211 0 : args = *save_args;
212 :
213 0 : request = args->buf;
214 :
215 : /* Replace slashes with spaces, stop at the end of the path */
216 0 : i = 0;
217 0 : while (i < vec_len (request))
218 : {
219 0 : if (request[i] == '/')
220 0 : request[i] = ' ';
221 0 : else if (request[i] == ' ')
222 : {
223 : /* vlib_cli_input is vector-based, no need for a NULL */
224 0 : vec_set_len (request, i);
225 0 : break;
226 : }
227 0 : i++;
228 : }
229 :
230 : /* Generate the html header */
231 0 : html = format (0, html_header_template, request /* title */ );
232 :
233 : /* Run the command */
234 0 : unformat_init_vector (&input, vec_dup (request));
235 0 : vlib_cli_input (vm, &input, hcs_cli_output, (uword) &reply);
236 0 : unformat_free (&input);
237 0 : request = 0;
238 :
239 : /* Generate the html page */
240 0 : html = format (html, "%v", reply);
241 0 : html = format (html, html_footer);
242 :
243 : /* Send it */
244 0 : rpc_args = clib_mem_alloc (sizeof (*args));
245 0 : clib_memcpy_fast (rpc_args, args, sizeof (*args));
246 0 : rpc_args->buf = html;
247 :
248 0 : session_send_rpc_evt_to_thread_force (args->thread_index, send_data_to_http,
249 : rpc_args);
250 :
251 0 : vec_free (reply);
252 0 : vec_free (args->buf);
253 0 : hcs_cli_process_free (args);
254 :
255 0 : return (0);
256 : }
257 :
258 : static void
259 0 : alloc_cli_process (hcs_cli_args_t *args)
260 : {
261 0 : hcs_main_t *hcm = &hcs_main;
262 0 : vlib_main_t *vm = hcm->vlib_main;
263 : hcs_cli_args_t **save_args;
264 : vlib_node_t *n;
265 : uword l;
266 :
267 0 : l = vec_len (hcm->free_http_cli_process_node_indices);
268 0 : if (l > 0)
269 : {
270 0 : n = vlib_get_node (vm, hcm->free_http_cli_process_node_indices[l - 1]);
271 0 : vlib_node_set_state (vm, n->index, VLIB_NODE_STATE_POLLING);
272 0 : vec_set_len (hcm->free_http_cli_process_node_indices, l - 1);
273 : }
274 : else
275 : {
276 : static vlib_node_registration_t r = {
277 : .function = hcs_cli_process,
278 : .type = VLIB_NODE_TYPE_PROCESS,
279 : .process_log2_n_stack_bytes = 16,
280 : .runtime_data_bytes = sizeof (void *),
281 : };
282 :
283 0 : vlib_register_node (vm, &r, "http-cli-%d", l);
284 :
285 0 : n = vlib_get_node (vm, r.index);
286 : }
287 :
288 : /* Save the node index in the args. It won't be zero. */
289 0 : args->node_index = n->index;
290 :
291 : /* Save the args (pointer) in the node runtime */
292 0 : save_args = vlib_node_get_runtime_data (vm, n->index);
293 0 : *save_args = clib_mem_alloc (sizeof (*args));
294 0 : clib_memcpy_fast (*save_args, args, sizeof (*args));
295 :
296 0 : vlib_start_process (vm, n->runtime_index);
297 0 : }
298 :
299 : static void
300 0 : alloc_cli_process_callback (void *cb_args)
301 : {
302 0 : alloc_cli_process ((hcs_cli_args_t *) cb_args);
303 0 : }
304 :
305 : static int
306 0 : hcs_ts_rx_callback (session_t *ts)
307 : {
308 0 : hcs_cli_args_t args = {};
309 : hcs_session_t *hs;
310 : http_msg_t msg;
311 : int rv;
312 :
313 0 : hs = hcs_session_get (ts->thread_index, ts->opaque);
314 :
315 : /* Read the http message header */
316 0 : rv = svm_fifo_dequeue (ts->rx_fifo, sizeof (msg), (u8 *) &msg);
317 0 : ASSERT (rv == sizeof (msg));
318 :
319 0 : if (msg.type != HTTP_MSG_REQUEST || msg.method_type != HTTP_REQ_GET)
320 : {
321 0 : hs->tx_buf = 0;
322 0 : start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED);
323 0 : return 0;
324 : }
325 :
326 : /* send the command to a new/recycled vlib process */
327 0 : vec_validate (args.buf, msg.data.len - 1);
328 0 : rv = svm_fifo_dequeue (ts->rx_fifo, msg.data.len, args.buf);
329 0 : ASSERT (rv == msg.data.len);
330 0 : vec_set_len (args.buf, rv);
331 :
332 0 : args.hs_index = hs->session_index;
333 0 : args.thread_index = ts->thread_index;
334 :
335 : /* Send RPC request to main thread */
336 0 : if (vlib_get_thread_index () != 0)
337 0 : vlib_rpc_call_main_thread (alloc_cli_process_callback, (u8 *) &args,
338 : sizeof (args));
339 : else
340 0 : alloc_cli_process (&args);
341 0 : return 0;
342 : }
343 :
344 : static int
345 0 : hcs_ts_tx_callback (session_t *ts)
346 : {
347 : hcs_session_t *hs;
348 : u32 to_send;
349 : int rv;
350 :
351 0 : hs = hcs_session_get (ts->thread_index, ts->opaque);
352 0 : if (!hs || !hs->tx_buf)
353 0 : return 0;
354 :
355 0 : to_send = vec_len (hs->tx_buf) - hs->tx_offset;
356 0 : rv = svm_fifo_enqueue (ts->tx_fifo, to_send, hs->tx_buf + hs->tx_offset);
357 :
358 0 : if (rv <= 0)
359 : {
360 0 : svm_fifo_add_want_deq_ntf (ts->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
361 0 : return 0;
362 : }
363 :
364 0 : if (rv < to_send)
365 : {
366 0 : hs->tx_offset += rv;
367 0 : svm_fifo_add_want_deq_ntf (ts->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
368 : }
369 : else
370 : {
371 0 : vec_free (hs->tx_buf);
372 : }
373 :
374 0 : if (svm_fifo_set_event (ts->tx_fifo))
375 0 : session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
376 :
377 0 : return 0;
378 : }
379 :
380 : static int
381 0 : hcs_ts_accept_callback (session_t *ts)
382 : {
383 : hcs_session_t *hs;
384 :
385 0 : hs = hcs_session_alloc (ts->thread_index);
386 0 : hs->vpp_session_index = ts->session_index;
387 :
388 0 : ts->opaque = hs->session_index;
389 0 : ts->session_state = SESSION_STATE_READY;
390 :
391 0 : return 0;
392 : }
393 :
394 : static int
395 0 : hcs_ts_connected_callback (u32 app_index, u32 api_context, session_t *s,
396 : session_error_t err)
397 : {
398 0 : clib_warning ("called...");
399 0 : return -1;
400 : }
401 :
402 : static void
403 0 : hcs_ts_disconnect_callback (session_t *s)
404 : {
405 0 : hcs_main_t *hcm = &hcs_main;
406 0 : vnet_disconnect_args_t _a = { 0 }, *a = &_a;
407 :
408 0 : a->handle = session_handle (s);
409 0 : a->app_index = hcm->app_index;
410 0 : vnet_disconnect_session (a);
411 0 : }
412 :
413 : static void
414 0 : hcs_ts_reset_callback (session_t *s)
415 : {
416 0 : hcs_main_t *hcm = &hcs_main;
417 0 : vnet_disconnect_args_t _a = { 0 }, *a = &_a;
418 :
419 0 : a->handle = session_handle (s);
420 0 : a->app_index = hcm->app_index;
421 0 : vnet_disconnect_session (a);
422 0 : }
423 :
424 : static void
425 0 : hcs_ts_cleanup_callback (session_t *s, session_cleanup_ntf_t ntf)
426 : {
427 : hcs_session_t *hs;
428 :
429 0 : if (ntf == SESSION_CLEANUP_TRANSPORT)
430 0 : return;
431 :
432 0 : hs = hcs_session_get (s->thread_index, s->opaque);
433 0 : if (!hs)
434 0 : return;
435 :
436 0 : vec_free (hs->tx_buf);
437 0 : hcs_session_free (hs);
438 : }
439 :
440 : static int
441 0 : hcs_add_segment_callback (u32 client_index, u64 segment_handle)
442 : {
443 0 : return 0;
444 : }
445 :
446 : static int
447 0 : hcs_del_segment_callback (u32 client_index, u64 segment_handle)
448 : {
449 0 : return 0;
450 : }
451 :
452 : static session_cb_vft_t hcs_session_cb_vft = {
453 : .session_accept_callback = hcs_ts_accept_callback,
454 : .session_disconnect_callback = hcs_ts_disconnect_callback,
455 : .session_connected_callback = hcs_ts_connected_callback,
456 : .add_segment_callback = hcs_add_segment_callback,
457 : .del_segment_callback = hcs_del_segment_callback,
458 : .builtin_app_rx_callback = hcs_ts_rx_callback,
459 : .builtin_app_tx_callback = hcs_ts_tx_callback,
460 : .session_reset_callback = hcs_ts_reset_callback,
461 : .session_cleanup_callback = hcs_ts_cleanup_callback,
462 : };
463 :
464 : static int
465 3 : hcs_attach ()
466 : {
467 3 : vnet_app_add_cert_key_pair_args_t _ck_pair, *ck_pair = &_ck_pair;
468 3 : hcs_main_t *hcm = &hcs_main;
469 : u64 options[APP_OPTIONS_N_OPTIONS];
470 3 : vnet_app_attach_args_t _a, *a = &_a;
471 3 : u32 segment_size = 128 << 20;
472 :
473 3 : clib_memset (a, 0, sizeof (*a));
474 3 : clib_memset (options, 0, sizeof (options));
475 :
476 3 : if (hcm->private_segment_size)
477 0 : segment_size = hcm->private_segment_size;
478 :
479 3 : a->api_client_index = ~0;
480 3 : a->name = format (0, "http_cli_server");
481 3 : a->session_cb_vft = &hcs_session_cb_vft;
482 3 : a->options = options;
483 3 : a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
484 3 : a->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = segment_size;
485 3 : a->options[APP_OPTIONS_RX_FIFO_SIZE] =
486 3 : hcm->fifo_size ? hcm->fifo_size : 8 << 10;
487 3 : a->options[APP_OPTIONS_TX_FIFO_SIZE] =
488 3 : hcm->fifo_size ? hcm->fifo_size : 32 << 10;
489 3 : a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
490 3 : a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = hcm->prealloc_fifos;
491 :
492 3 : if (vnet_application_attach (a))
493 : {
494 0 : vec_free (a->name);
495 0 : clib_warning ("failed to attach server");
496 0 : return -1;
497 : }
498 3 : vec_free (a->name);
499 3 : hcm->app_index = a->app_index;
500 :
501 3 : clib_memset (ck_pair, 0, sizeof (*ck_pair));
502 3 : ck_pair->cert = (u8 *) test_srv_crt_rsa;
503 3 : ck_pair->key = (u8 *) test_srv_key_rsa;
504 3 : ck_pair->cert_len = test_srv_crt_rsa_len;
505 3 : ck_pair->key_len = test_srv_key_rsa_len;
506 3 : vnet_app_add_cert_key_pair (ck_pair);
507 3 : hcm->ckpair_index = ck_pair->index;
508 :
509 3 : return 0;
510 : }
511 :
512 : static int
513 3 : hcs_transport_needs_crypto (transport_proto_t proto)
514 : {
515 3 : return proto == TRANSPORT_PROTO_TLS || proto == TRANSPORT_PROTO_DTLS ||
516 : proto == TRANSPORT_PROTO_QUIC;
517 : }
518 :
519 : static int
520 3 : hcs_listen ()
521 : {
522 3 : session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
523 3 : hcs_main_t *hcm = &hcs_main;
524 3 : vnet_listen_args_t _a, *a = &_a;
525 3 : char *uri = "tcp://0.0.0.0/80";
526 : u8 need_crypto;
527 : int rv;
528 :
529 3 : clib_memset (a, 0, sizeof (*a));
530 3 : a->app_index = hcm->app_index;
531 :
532 3 : if (hcm->uri)
533 0 : uri = (char *) hcm->uri;
534 :
535 3 : if (parse_uri (uri, &sep))
536 0 : return -1;
537 :
538 3 : need_crypto = hcs_transport_needs_crypto (sep.transport_proto);
539 :
540 3 : sep.transport_proto = TRANSPORT_PROTO_HTTP;
541 3 : clib_memcpy (&a->sep_ext, &sep, sizeof (sep));
542 :
543 3 : if (need_crypto)
544 : {
545 0 : session_endpoint_alloc_ext_cfg (&a->sep_ext,
546 : TRANSPORT_ENDPT_EXT_CFG_CRYPTO);
547 0 : a->sep_ext.ext_cfg->crypto.ckpair_index = hcm->ckpair_index;
548 : }
549 :
550 3 : rv = vnet_listen (a);
551 :
552 3 : if (need_crypto)
553 0 : clib_mem_free (a->sep_ext.ext_cfg);
554 :
555 3 : return rv;
556 : }
557 :
558 : static void
559 0 : hcs_detach ()
560 : {
561 0 : vnet_app_detach_args_t _a, *a = &_a;
562 0 : hcs_main_t *hcm = &hcs_main;
563 0 : a->app_index = hcm->app_index;
564 0 : a->api_client_index = APP_INVALID_INDEX;
565 0 : hcm->app_index = ~0;
566 0 : vnet_application_detach (a);
567 0 : }
568 :
569 : static int
570 3 : hcs_create (vlib_main_t *vm)
571 : {
572 3 : vlib_thread_main_t *vtm = vlib_get_thread_main ();
573 3 : hcs_main_t *hcm = &hcs_main;
574 : u32 num_threads;
575 :
576 3 : num_threads = 1 /* main thread */ + vtm->n_threads;
577 3 : vec_validate (hcm->sessions, num_threads - 1);
578 :
579 3 : if (hcs_attach ())
580 : {
581 0 : clib_warning ("failed to attach server");
582 0 : return -1;
583 : }
584 3 : if (hcs_listen ())
585 : {
586 0 : hcs_detach ();
587 0 : clib_warning ("failed to start listening");
588 0 : return -1;
589 : }
590 :
591 3 : return 0;
592 : }
593 :
594 : static clib_error_t *
595 3 : hcs_create_command_fn (vlib_main_t *vm, unformat_input_t *input,
596 : vlib_cli_command_t *cmd)
597 : {
598 3 : unformat_input_t _line_input, *line_input = &_line_input;
599 3 : hcs_main_t *hcm = &hcs_main;
600 : u64 seg_size;
601 : int rv;
602 :
603 3 : hcm->prealloc_fifos = 0;
604 3 : hcm->private_segment_size = 0;
605 3 : hcm->fifo_size = 0;
606 :
607 : /* Get a line of input. */
608 3 : if (!unformat_user (input, unformat_line_input, line_input))
609 3 : goto start_server;
610 :
611 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
612 : {
613 0 : if (unformat (line_input, "prealloc-fifos %d", &hcm->prealloc_fifos))
614 : ;
615 0 : else if (unformat (line_input, "private-segment-size %U",
616 : unformat_memory_size, &seg_size))
617 0 : hcm->private_segment_size = seg_size;
618 0 : else if (unformat (line_input, "fifo-size %d", &hcm->fifo_size))
619 0 : hcm->fifo_size <<= 10;
620 0 : else if (unformat (line_input, "uri %s", &hcm->uri))
621 : ;
622 : else
623 : {
624 0 : unformat_free (line_input);
625 0 : return clib_error_return (0, "unknown input `%U'",
626 : format_unformat_error, line_input);
627 : }
628 : }
629 :
630 0 : unformat_free (line_input);
631 :
632 3 : start_server:
633 :
634 3 : if (hcm->app_index != (u32) ~0)
635 0 : return clib_error_return (0, "test http server is already running");
636 :
637 3 : vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
638 :
639 3 : rv = hcs_create (vm);
640 3 : switch (rv)
641 : {
642 3 : case 0:
643 3 : break;
644 0 : default:
645 0 : return clib_error_return (0, "server_create returned %d", rv);
646 : }
647 :
648 3 : return 0;
649 : }
650 :
651 203447 : VLIB_CLI_COMMAND (hcs_create_command, static) = {
652 : .path = "http cli server",
653 : .short_help = "http cli server [uri <uri>] [fifo-size <nbytes>] "
654 : "[private-segment-size <nMG>] [prealloc-fifos <n>]",
655 : .function = hcs_create_command_fn,
656 : };
657 :
658 : static clib_error_t *
659 559 : hcs_main_init (vlib_main_t *vm)
660 : {
661 559 : hcs_main_t *hcs = &hcs_main;
662 :
663 559 : hcs->app_index = ~0;
664 559 : hcs->vlib_main = vm;
665 559 : return 0;
666 : }
667 :
668 1679 : VLIB_INIT_FUNCTION (hcs_main_init);
669 :
670 : /*
671 : * fd.io coding-style-patch-verification: ON
672 : *
673 : * Local Variables:
674 : * eval: (c-set-style "gnu")
675 : * End:
676 : */
|