blob: 4f0e211c7bef94cf29403f4d0d4d24e130b29dcf [file] [log] [blame]
Florin Corase04c2992017-03-01 08:17:34 -08001/*
2* Copyright (c) 2015-2017 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/vnet.h>
17#include <vlibmemory/api.h>
18#include <vnet/session/application.h>
19#include <vnet/session/application_interface.h>
20
Florin Coras6cf30ad2017-04-04 23:08:23 -070021/* define message IDs */
22#include <vpp/api/vpe_msg_enum.h>
23
24/* define message structures */
25#define vl_typedefs
26#include <vpp/api/vpe_all_api_h.h>
27#undef vl_typedefs
28
29/* define generated endian-swappers */
30#define vl_endianfun
31#include <vpp/api/vpe_all_api_h.h>
32#undef vl_endianfun
33
34/* instantiate all the print functions we know about */
35#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
36#define vl_printfun
37#include <vpp/api/vpe_all_api_h.h>
38#undef vl_printfun
39
Florin Corasd79b41e2017-03-04 05:37:52 -080040typedef struct
41{
42 u8 *rx_buf;
43 unix_shared_memory_queue_t **vpp_queue;
Florin Coras6cf30ad2017-04-04 23:08:23 -070044 u64 byte_index;
45
46 /* Sever's event queue */
47 unix_shared_memory_queue_t *vl_input_queue;
48
49 /* API client handle */
50 u32 my_client_index;
51
52 u32 app_index;
53
54 /* process node index for evnt scheduling */
55 u32 node_index;
Florin Corasd79b41e2017-03-04 05:37:52 -080056 vlib_main_t *vlib_main;
57} builtin_server_main_t;
58
59builtin_server_main_t builtin_server_main;
60
Florin Corase04c2992017-03-01 08:17:34 -080061int
62builtin_session_accept_callback (stream_session_t * s)
63{
Florin Corasd79b41e2017-03-04 05:37:52 -080064 builtin_server_main_t *bsm = &builtin_server_main;
Florin Corasd79b41e2017-03-04 05:37:52 -080065
66 bsm->vpp_queue[s->thread_index] =
67 session_manager_get_vpp_event_queue (s->thread_index);
Florin Corase04c2992017-03-01 08:17:34 -080068 s->session_state = SESSION_STATE_READY;
Florin Coras6792ec02017-03-13 03:49:51 -070069 bsm->byte_index = 0;
Florin Corase04c2992017-03-01 08:17:34 -080070 return 0;
71}
72
73void
74builtin_session_disconnect_callback (stream_session_t * s)
75{
Florin Coras6cf30ad2017-04-04 23:08:23 -070076 builtin_server_main_t *bsm = &builtin_server_main;
77 vnet_disconnect_args_t _a, *a = &_a;
Florin Corasd79b41e2017-03-04 05:37:52 -080078
Florin Coras6cf30ad2017-04-04 23:08:23 -070079 a->handle = stream_session_handle (s);
80 a->app_index = bsm->app_index;
81 vnet_disconnect_session (a);
Florin Corase04c2992017-03-01 08:17:34 -080082}
83
Florin Corasd79b41e2017-03-04 05:37:52 -080084void
85builtin_session_reset_callback (stream_session_t * s)
86{
87 clib_warning ("called.. ");
88
89 stream_session_cleanup (s);
90}
91
92
Florin Corase04c2992017-03-01 08:17:34 -080093int
Florin Coras6cf30ad2017-04-04 23:08:23 -070094builtin_session_connected_callback (u32 app_index, u32 api_context,
Florin Corase04c2992017-03-01 08:17:34 -080095 stream_session_t * s, u8 is_fail)
96{
97 clib_warning ("called...");
98 return -1;
99}
100
101int
102builtin_add_segment_callback (u32 client_index,
103 const u8 * seg_name, u32 seg_size)
104{
105 clib_warning ("called...");
106 return -1;
107}
108
109int
110builtin_redirect_connect_callback (u32 client_index, void *mp)
111{
112 clib_warning ("called...");
113 return -1;
114}
115
Florin Coras6792ec02017-03-13 03:49:51 -0700116void
117test_bytes (builtin_server_main_t * bsm, int actual_transfer)
Florin Corase04c2992017-03-01 08:17:34 -0800118{
Florin Coras6792ec02017-03-13 03:49:51 -0700119 int i;
120
121 for (i = 0; i < actual_transfer; i++)
122 {
123 if (bsm->rx_buf[i] != ((bsm->byte_index + i) & 0xff))
124 {
Florin Coras6cf30ad2017-04-04 23:08:23 -0700125 clib_warning ("at %lld expected %d got %d", bsm->byte_index + i,
Florin Coras6792ec02017-03-13 03:49:51 -0700126 (bsm->byte_index + i) & 0xff, bsm->rx_buf[i]);
127 }
128 }
129 bsm->byte_index += actual_transfer;
130}
131
132int
133builtin_server_rx_callback (stream_session_t * s)
134{
135 u32 n_written, max_dequeue, max_enqueue, max_transfer;
136 int actual_transfer;
137 svm_fifo_t *tx_fifo, *rx_fifo;
Florin Corasd79b41e2017-03-04 05:37:52 -0800138 builtin_server_main_t *bsm = &builtin_server_main;
139 session_fifo_event_t evt;
140 static int serial_number = 0;
141
Dave Barachacd2a6a2017-05-16 17:41:34 -0400142 tx_fifo = s->server_tx_fifo;
143 rx_fifo = s->server_rx_fifo;
144
Florin Coras6792ec02017-03-13 03:49:51 -0700145 max_dequeue = svm_fifo_max_dequeue (s->server_rx_fifo);
146 max_enqueue = svm_fifo_max_enqueue (s->server_tx_fifo);
147
148 if (PREDICT_FALSE (max_dequeue == 0))
Dave Barachacd2a6a2017-05-16 17:41:34 -0400149 return 0;
Florin Corasd79b41e2017-03-04 05:37:52 -0800150
151 /* Number of bytes we're going to copy */
Florin Coras6792ec02017-03-13 03:49:51 -0700152 max_transfer = (max_dequeue < max_enqueue) ? max_dequeue : max_enqueue;
Florin Corasd79b41e2017-03-04 05:37:52 -0800153
Florin Coras6792ec02017-03-13 03:49:51 -0700154 /* No space in tx fifo */
155 if (PREDICT_FALSE (max_transfer == 0))
Florin Corasd79b41e2017-03-04 05:37:52 -0800156 {
Florin Coras6792ec02017-03-13 03:49:51 -0700157 /* XXX timeout for session that are stuck */
158
Florin Coras3e350af2017-03-30 02:54:28 -0700159 rx_event:
Florin Coras6792ec02017-03-13 03:49:51 -0700160 /* Program self-tap to retry */
161 if (svm_fifo_set_event (rx_fifo))
162 {
163 evt.fifo = rx_fifo;
164 evt.event_type = FIFO_EVENT_BUILTIN_RX;
165 evt.event_id = 0;
166 unix_shared_memory_queue_add (bsm->vpp_queue[s->thread_index],
167 (u8 *) & evt,
168 0 /* do wait for mutex */ );
169 }
170
Florin Corasd79b41e2017-03-04 05:37:52 -0800171 return 0;
172 }
173
Florin Coras6792ec02017-03-13 03:49:51 -0700174 vec_validate (bsm->rx_buf, max_transfer - 1);
175 _vec_len (bsm->rx_buf) = max_transfer;
176
Florin Corasa5464812017-04-19 13:00:05 -0700177 actual_transfer = svm_fifo_dequeue_nowait (rx_fifo, max_transfer,
Florin Coras6792ec02017-03-13 03:49:51 -0700178 bsm->rx_buf);
179 ASSERT (actual_transfer == max_transfer);
180
181// test_bytes (bsm, actual_transfer);
Florin Corasd79b41e2017-03-04 05:37:52 -0800182
183 /*
184 * Echo back
185 */
186
Florin Corasa5464812017-04-19 13:00:05 -0700187 n_written = svm_fifo_enqueue_nowait (tx_fifo, actual_transfer, bsm->rx_buf);
Florin Coras3e350af2017-03-30 02:54:28 -0700188
189 if (n_written != max_transfer)
190 clib_warning ("short trout!");
Florin Corasd79b41e2017-03-04 05:37:52 -0800191
Florin Coras6792ec02017-03-13 03:49:51 -0700192 if (svm_fifo_set_event (tx_fifo))
193 {
194 /* Fabricate TX event, send to vpp */
195 evt.fifo = tx_fifo;
Florin Corasa5464812017-04-19 13:00:05 -0700196 evt.event_type = FIFO_EVENT_APP_TX;
Florin Coras6792ec02017-03-13 03:49:51 -0700197 evt.event_id = serial_number++;
Florin Corasd79b41e2017-03-04 05:37:52 -0800198
Florin Coras6792ec02017-03-13 03:49:51 -0700199 unix_shared_memory_queue_add (bsm->vpp_queue[s->thread_index],
200 (u8 *) & evt, 0 /* do wait for mutex */ );
201 }
Florin Corasd79b41e2017-03-04 05:37:52 -0800202
Florin Coras3e350af2017-03-30 02:54:28 -0700203 if (PREDICT_FALSE (max_enqueue < max_dequeue))
204 goto rx_event;
205
Florin Corase04c2992017-03-01 08:17:34 -0800206 return 0;
207}
208
209static session_cb_vft_t builtin_session_cb_vft = {
210 .session_accept_callback = builtin_session_accept_callback,
211 .session_disconnect_callback = builtin_session_disconnect_callback,
212 .session_connected_callback = builtin_session_connected_callback,
213 .add_segment_callback = builtin_add_segment_callback,
214 .redirect_connect_callback = builtin_redirect_connect_callback,
Florin Corasd79b41e2017-03-04 05:37:52 -0800215 .builtin_server_rx_callback = builtin_server_rx_callback,
216 .session_reset_callback = builtin_session_reset_callback
Florin Corase04c2992017-03-01 08:17:34 -0800217};
218
Florin Coras6cf30ad2017-04-04 23:08:23 -0700219/* Abuse VPP's input queue */
Florin Corase04c2992017-03-01 08:17:34 -0800220static int
Florin Coras6cf30ad2017-04-04 23:08:23 -0700221create_api_loopback (vlib_main_t * vm)
Florin Corase04c2992017-03-01 08:17:34 -0800222{
Florin Coras6cf30ad2017-04-04 23:08:23 -0700223 builtin_server_main_t *bsm = &builtin_server_main;
224 vl_api_memclnt_create_t _m, *mp = &_m;
225 extern void vl_api_memclnt_create_t_handler (vl_api_memclnt_create_t *);
226 api_main_t *am = &api_main;
227 vl_shmem_hdr_t *shmem_hdr;
228 uword *event_data = 0, event_type;
229 int resolved = 0;
Florin Corasd79b41e2017-03-04 05:37:52 -0800230
Florin Coras6cf30ad2017-04-04 23:08:23 -0700231 /*
232 * Create a "loopback" API client connection
233 * Don't do things like this unless you know what you're doing...
234 */
235
236 shmem_hdr = am->shmem_hdr;
237 bsm->vl_input_queue = shmem_hdr->vl_input_queue;
238 memset (mp, 0, sizeof (*mp));
239 mp->_vl_msg_id = VL_API_MEMCLNT_CREATE;
240 mp->context = 0xFEEDFACE;
Damjan Marion7bee80c2017-04-26 15:32:12 +0200241 mp->input_queue = pointer_to_uword (bsm->vl_input_queue);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700242 strncpy ((char *) mp->name, "tcp_test_server", sizeof (mp->name) - 1);
243
244 vl_api_memclnt_create_t_handler (mp);
245
246 /* Wait for reply */
247 bsm->node_index = vlib_get_current_process (vm)->node_runtime.node_index;
248 vlib_process_wait_for_event_or_clock (vm, 1.0);
249 event_type = vlib_process_get_events (vm, &event_data);
250 switch (event_type)
251 {
252 case 1:
253 resolved = 1;
254 break;
255 case ~0:
256 /* timed out */
257 break;
258 default:
259 clib_warning ("unknown event_type %d", event_type);
260 }
261 if (!resolved)
262 return -1;
263
264 return 0;
265}
266
267static int
268server_attach ()
269{
270 builtin_server_main_t *bsm = &builtin_server_main;
271 u8 segment_name[128];
272 u64 options[SESSION_OPTIONS_N_OPTIONS];
273 vnet_app_attach_args_t _a, *a = &_a;
Florin Corase04c2992017-03-01 08:17:34 -0800274
275 memset (a, 0, sizeof (*a));
276 memset (options, 0, sizeof (options));
277
Florin Coras6cf30ad2017-04-04 23:08:23 -0700278 a->api_client_index = bsm->my_client_index;
Florin Corase04c2992017-03-01 08:17:34 -0800279 a->session_cb_vft = &builtin_session_cb_vft;
280 a->options = options;
Dave Barach10d8cc62017-05-30 09:30:07 -0400281 a->options[SESSION_OPTIONS_SEGMENT_SIZE] = 512 << 20;
282 a->options[SESSION_OPTIONS_RX_FIFO_SIZE] = 64 << 10;
283 a->options[SESSION_OPTIONS_TX_FIFO_SIZE] = 64 << 10;
Florin Corasa5464812017-04-19 13:00:05 -0700284 a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_BUILTIN_APP;
Dave Barach10d8cc62017-05-30 09:30:07 -0400285 a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = 8192;
Florin Corase04c2992017-03-01 08:17:34 -0800286 a->segment_name = segment_name;
287 a->segment_name_length = ARRAY_LEN (segment_name);
288
Florin Coras6cf30ad2017-04-04 23:08:23 -0700289 if (vnet_application_attach (a))
290 {
291 clib_warning ("failed to attach server");
292 return -1;
293 }
294 bsm->app_index = a->app_index;
295 return 0;
296}
297
298static int
299server_listen ()
300{
301 builtin_server_main_t *bsm = &builtin_server_main;
302 vnet_bind_args_t _a, *a = &_a;
303 memset (a, 0, sizeof (*a));
304 a->app_index = bsm->app_index;
305 a->uri = "tcp://0.0.0.0/1234";
Florin Corase04c2992017-03-01 08:17:34 -0800306 return vnet_bind_uri (a);
307}
308
Florin Coras6cf30ad2017-04-04 23:08:23 -0700309static int
310server_create (vlib_main_t * vm)
311{
312 builtin_server_main_t *bsm = &builtin_server_main;
313 u32 num_threads;
314 vlib_thread_main_t *vtm = vlib_get_thread_main ();
315
316 if (bsm->my_client_index == (u32) ~ 0)
317 {
318 if (create_api_loopback (vm))
319 return -1;
320 }
321
322 num_threads = 1 /* main thread */ + vtm->n_threads;
323 vec_validate (builtin_server_main.vpp_queue, num_threads - 1);
324
325 if (server_attach ())
326 {
327 clib_warning ("failed to attach server");
328 return -1;
329 }
330 if (server_listen ())
331 {
332 clib_warning ("failed to start listening");
333 return -1;
334 }
335 return 0;
336}
337
338/* Get our api client index */
339static void
340vl_api_memclnt_create_reply_t_handler (vl_api_memclnt_create_reply_t * mp)
341{
342 vlib_main_t *vm = vlib_get_main ();
343 builtin_server_main_t *bsm = &builtin_server_main;
344 bsm->my_client_index = mp->index;
345 vlib_process_signal_event (vm, bsm->node_index, 1 /* evt */ ,
346 0 /* data */ );
347}
348
349#define foreach_tcp_builtin_server_api_msg \
350_(MEMCLNT_CREATE_REPLY, memclnt_create_reply) \
351
352static clib_error_t *
353tcp_builtin_server_api_hookup (vlib_main_t * vm)
354{
355 vl_msg_api_msg_config_t _c, *c = &_c;
356
357 /* Hook up client-side static APIs to our handlers */
358#define _(N,n) do { \
359 c->id = VL_API_##N; \
360 c->name = #n; \
361 c->handler = vl_api_##n##_t_handler; \
362 c->cleanup = vl_noop_handler; \
363 c->endian = vl_api_##n##_t_endian; \
364 c->print = vl_api_##n##_t_print; \
365 c->size = sizeof(vl_api_##n##_t); \
366 c->traced = 1; /* trace, so these msgs print */ \
367 c->replay = 0; /* don't replay client create/delete msgs */ \
368 c->message_bounce = 0; /* don't bounce this message */ \
369 vl_msg_api_config(c);} while (0);
370
371 foreach_tcp_builtin_server_api_msg;
372#undef _
373
374 return 0;
375}
376
Florin Corase04c2992017-03-01 08:17:34 -0800377static clib_error_t *
378server_create_command_fn (vlib_main_t * vm,
379 unformat_input_t * input, vlib_cli_command_t * cmd)
380{
381 int rv;
382#if 0
383 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
384 {
385 if (unformat (input, "whatever %d", &whatever))
386 ;
387 else
388 return clib_error_return (0, "unknown input `%U'",
389 format_unformat_error, input);
390 }
391#endif
392
Florin Coras6cf30ad2017-04-04 23:08:23 -0700393 tcp_builtin_server_api_hookup (vm);
Florin Corasd79b41e2017-03-04 05:37:52 -0800394 vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
Florin Corase04c2992017-03-01 08:17:34 -0800395 rv = server_create (vm);
396 switch (rv)
397 {
398 case 0:
399 break;
400 default:
401 return clib_error_return (0, "server_create returned %d", rv);
402 }
403 return 0;
404}
405
Florin Corasd79b41e2017-03-04 05:37:52 -0800406/* *INDENT-OFF* */
Florin Corase04c2992017-03-01 08:17:34 -0800407VLIB_CLI_COMMAND (server_create_command, static) =
408{
Florin Coras6cf30ad2017-04-04 23:08:23 -0700409 .path = "test tcp server",
410 .short_help = "test tcp server",
Florin Corasd79b41e2017-03-04 05:37:52 -0800411 .function = server_create_command_fn,
412};
413/* *INDENT-ON* */
Florin Corase04c2992017-03-01 08:17:34 -0800414
Florin Coras6cf30ad2017-04-04 23:08:23 -0700415clib_error_t *
416builtin_tcp_server_main_init (vlib_main_t * vm)
417{
418 builtin_server_main_t *bsm = &builtin_server_main;
419 bsm->my_client_index = ~0;
420 return 0;
421}
422
423VLIB_INIT_FUNCTION (builtin_tcp_server_main_init);
424
Florin Corase04c2992017-03-01 08:17:34 -0800425/*
426* fd.io coding-style-patch-verification: ON
427*
428* Local Variables:
429* eval: (c-set-style "gnu")
430* End:
431*/