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/vnet.h>
17 : #include <vlibmemory/api.h>
18 : #include <vnet/session/application.h>
19 : #include <vnet/session/application_interface.h>
20 : #include <hs_apps/proxy.h>
21 : #include <vnet/tcp/tcp.h>
22 :
23 : proxy_main_t proxy_main;
24 :
25 : #define TCP_MSS 1460
26 :
27 : typedef struct
28 : {
29 : session_endpoint_cfg_t sep;
30 : u32 app_index;
31 : u32 api_context;
32 : } proxy_connect_args_t;
33 :
34 : static void
35 0 : proxy_cb_fn (void *data, u32 data_len)
36 : {
37 0 : proxy_connect_args_t *pa = (proxy_connect_args_t *) data;
38 : vnet_connect_args_t a;
39 :
40 0 : clib_memset (&a, 0, sizeof (a));
41 0 : a.api_context = pa->api_context;
42 0 : a.app_index = pa->app_index;
43 0 : clib_memcpy (&a.sep_ext, &pa->sep, sizeof (pa->sep));
44 0 : vnet_connect (&a);
45 0 : if (a.sep_ext.ext_cfg)
46 0 : clib_mem_free (a.sep_ext.ext_cfg);
47 0 : }
48 :
49 : static void
50 0 : proxy_call_main_thread (vnet_connect_args_t * a)
51 : {
52 0 : if (vlib_get_thread_index () == 0)
53 : {
54 0 : vnet_connect (a);
55 0 : if (a->sep_ext.ext_cfg)
56 0 : clib_mem_free (a->sep_ext.ext_cfg);
57 : }
58 : else
59 : {
60 : proxy_connect_args_t args;
61 0 : args.api_context = a->api_context;
62 0 : args.app_index = a->app_index;
63 0 : clib_memcpy (&args.sep, &a->sep_ext, sizeof (a->sep_ext));
64 0 : vl_api_rpc_call_main_thread (proxy_cb_fn, (u8 *) & args, sizeof (args));
65 : }
66 0 : }
67 :
68 : static proxy_session_t *
69 0 : proxy_session_alloc (void)
70 : {
71 0 : proxy_main_t *pm = &proxy_main;
72 : proxy_session_t *ps;
73 :
74 0 : pool_get_zero (pm->sessions, ps);
75 0 : ps->ps_index = ps - pm->sessions;
76 :
77 0 : return ps;
78 : }
79 :
80 : static inline proxy_session_t *
81 0 : proxy_session_get (u32 ps_index)
82 : {
83 0 : proxy_main_t *pm = &proxy_main;
84 :
85 0 : return pool_elt_at_index (pm->sessions, ps_index);
86 : }
87 :
88 : static inline proxy_session_t *
89 0 : proxy_session_get_if_valid (u32 ps_index)
90 : {
91 0 : proxy_main_t *pm = &proxy_main;
92 :
93 0 : if (pool_is_free_index (pm->sessions, ps_index))
94 0 : return 0;
95 0 : return pool_elt_at_index (pm->sessions, ps_index);
96 : }
97 :
98 : static void
99 0 : proxy_session_free (proxy_session_t *ps)
100 : {
101 0 : proxy_main_t *pm = &proxy_main;
102 :
103 : if (CLIB_DEBUG > 0)
104 0 : clib_memset (ps, 0xFE, sizeof (*ps));
105 0 : pool_put (pm->sessions, ps);
106 0 : }
107 :
108 : static int
109 0 : proxy_session_postponed_free_rpc (void *arg)
110 : {
111 0 : uword ps_index = pointer_to_uword (arg);
112 0 : proxy_main_t *pm = &proxy_main;
113 0 : proxy_session_t *ps = 0;
114 :
115 0 : clib_spinlock_lock_if_init (&pm->sessions_lock);
116 :
117 0 : ps = proxy_session_get (ps_index);
118 0 : segment_manager_dealloc_fifos (ps->server_rx_fifo, ps->server_tx_fifo);
119 0 : proxy_session_free (ps);
120 :
121 0 : clib_spinlock_unlock_if_init (&pm->sessions_lock);
122 :
123 0 : return 0;
124 : }
125 :
126 : static void
127 0 : proxy_session_postponed_free (proxy_session_t *ps)
128 : {
129 0 : session_send_rpc_evt_to_thread (ps->po_thread_index,
130 : proxy_session_postponed_free_rpc,
131 0 : uword_to_pointer (ps->ps_index, void *));
132 0 : }
133 :
134 : static void
135 0 : proxy_try_close_session (session_t * s, int is_active_open)
136 : {
137 0 : proxy_main_t *pm = &proxy_main;
138 0 : proxy_session_t *ps = 0;
139 0 : vnet_disconnect_args_t _a, *a = &_a;
140 :
141 0 : clib_spinlock_lock_if_init (&pm->sessions_lock);
142 :
143 0 : ps = proxy_session_get (s->opaque);
144 :
145 0 : if (is_active_open)
146 : {
147 0 : a->handle = ps->vpp_active_open_handle;
148 0 : a->app_index = pm->active_open_app_index;
149 0 : vnet_disconnect_session (a);
150 0 : ps->ao_disconnected = 1;
151 :
152 0 : if (!ps->po_disconnected)
153 : {
154 0 : ASSERT (ps->vpp_server_handle != SESSION_INVALID_HANDLE);
155 0 : a->handle = ps->vpp_server_handle;
156 0 : a->app_index = pm->server_app_index;
157 0 : vnet_disconnect_session (a);
158 0 : ps->po_disconnected = 1;
159 : }
160 : }
161 : else
162 : {
163 0 : a->handle = ps->vpp_server_handle;
164 0 : a->app_index = pm->server_app_index;
165 0 : vnet_disconnect_session (a);
166 0 : ps->po_disconnected = 1;
167 :
168 0 : if (!ps->ao_disconnected && !ps->active_open_establishing)
169 : {
170 : /* Proxy session closed before active open */
171 0 : if (ps->vpp_active_open_handle != SESSION_INVALID_HANDLE)
172 : {
173 0 : a->handle = ps->vpp_active_open_handle;
174 0 : a->app_index = pm->active_open_app_index;
175 0 : vnet_disconnect_session (a);
176 : }
177 0 : ps->ao_disconnected = 1;
178 : }
179 : }
180 0 : clib_spinlock_unlock_if_init (&pm->sessions_lock);
181 0 : }
182 :
183 : static void
184 0 : proxy_try_delete_session (session_t * s, u8 is_active_open)
185 : {
186 0 : proxy_main_t *pm = &proxy_main;
187 0 : proxy_session_t *ps = 0;
188 :
189 0 : clib_spinlock_lock_if_init (&pm->sessions_lock);
190 :
191 0 : ps = proxy_session_get (s->opaque);
192 :
193 0 : if (is_active_open)
194 : {
195 0 : ps->vpp_active_open_handle = SESSION_INVALID_HANDLE;
196 :
197 : /* Revert master thread index change on connect notification */
198 0 : ps->server_rx_fifo->master_thread_index = ps->po_thread_index;
199 :
200 : /* Passive open already cleaned up */
201 0 : if (ps->vpp_server_handle == SESSION_INVALID_HANDLE)
202 : {
203 0 : ASSERT (s->rx_fifo->refcnt == 1);
204 :
205 : /* The two sides of the proxy on different threads */
206 0 : if (ps->po_thread_index != s->thread_index)
207 : {
208 : /* This is not the right thread to delete the fifos */
209 0 : s->rx_fifo = 0;
210 0 : s->tx_fifo = 0;
211 0 : proxy_session_postponed_free (ps);
212 : }
213 : else
214 0 : proxy_session_free (ps);
215 : }
216 : }
217 : else
218 : {
219 0 : ps->vpp_server_handle = SESSION_INVALID_HANDLE;
220 :
221 0 : if (ps->vpp_active_open_handle == SESSION_INVALID_HANDLE)
222 : {
223 0 : if (!ps->active_open_establishing)
224 0 : proxy_session_free (ps);
225 : }
226 : }
227 0 : clib_spinlock_unlock_if_init (&pm->sessions_lock);
228 0 : }
229 :
230 : static int
231 0 : common_fifo_tuning_callback (session_t * s, svm_fifo_t * f,
232 : session_ft_action_t act, u32 bytes)
233 : {
234 0 : proxy_main_t *pm = &proxy_main;
235 :
236 0 : segment_manager_t *sm = segment_manager_get (f->segment_manager);
237 0 : fifo_segment_t *fs = segment_manager_get_segment (sm, f->segment_index);
238 :
239 0 : u8 seg_usage = fifo_segment_get_mem_usage (fs);
240 0 : u32 fifo_in_use = svm_fifo_max_dequeue_prod (f);
241 0 : u32 fifo_size = svm_fifo_size (f);
242 0 : u8 fifo_usage = fifo_in_use * 100 / fifo_size;
243 0 : u8 update_size = 0;
244 :
245 0 : ASSERT (act < SESSION_FT_ACTION_N_ACTIONS);
246 :
247 0 : if (act == SESSION_FT_ACTION_ENQUEUED)
248 : {
249 0 : if (seg_usage < pm->low_watermark && fifo_usage > 50)
250 0 : update_size = fifo_in_use;
251 0 : else if (seg_usage < pm->high_watermark && fifo_usage > 80)
252 0 : update_size = fifo_in_use;
253 :
254 0 : update_size = clib_min (update_size, sm->max_fifo_size - fifo_size);
255 0 : if (update_size)
256 0 : svm_fifo_set_size (f, fifo_size + update_size);
257 : }
258 : else /* dequeued */
259 : {
260 0 : if (seg_usage > pm->high_watermark || fifo_usage < 20)
261 0 : update_size = bytes;
262 0 : else if (seg_usage > pm->low_watermark && fifo_usage < 50)
263 0 : update_size = (bytes / 2);
264 :
265 0 : ASSERT (fifo_size >= 4096);
266 0 : update_size = clib_min (update_size, fifo_size - 4096);
267 0 : if (update_size)
268 0 : svm_fifo_set_size (f, fifo_size - update_size);
269 : }
270 :
271 0 : return 0;
272 : }
273 :
274 : static int
275 0 : proxy_accept_callback (session_t * s)
276 : {
277 0 : proxy_main_t *pm = &proxy_main;
278 : proxy_session_t *ps;
279 :
280 0 : clib_spinlock_lock_if_init (&pm->sessions_lock);
281 :
282 0 : ps = proxy_session_alloc ();
283 0 : ps->vpp_server_handle = session_handle (s);
284 0 : ps->vpp_active_open_handle = SESSION_INVALID_HANDLE;
285 0 : ps->po_thread_index = s->thread_index;
286 :
287 0 : s->opaque = ps->ps_index;
288 :
289 0 : clib_spinlock_unlock_if_init (&pm->sessions_lock);
290 :
291 0 : s->session_state = SESSION_STATE_READY;
292 :
293 0 : return 0;
294 : }
295 :
296 : static void
297 0 : proxy_disconnect_callback (session_t * s)
298 : {
299 0 : proxy_try_close_session (s, 0 /* is_active_open */ );
300 0 : }
301 :
302 : static void
303 0 : proxy_reset_callback (session_t * s)
304 : {
305 0 : proxy_try_close_session (s, 0 /* is_active_open */ );
306 0 : }
307 :
308 : static int
309 0 : proxy_connected_callback (u32 app_index, u32 api_context,
310 : session_t * s, session_error_t err)
311 : {
312 0 : clib_warning ("called...");
313 0 : return -1;
314 : }
315 :
316 : static int
317 0 : proxy_add_segment_callback (u32 client_index, u64 segment_handle)
318 : {
319 0 : return 0;
320 : }
321 :
322 : static int
323 0 : proxy_transport_needs_crypto (transport_proto_t proto)
324 : {
325 0 : return proto == TRANSPORT_PROTO_TLS;
326 : }
327 :
328 : static int
329 0 : proxy_rx_callback (session_t * s)
330 : {
331 0 : proxy_main_t *pm = &proxy_main;
332 0 : u32 thread_index = vlib_get_thread_index ();
333 : svm_fifo_t *ao_tx_fifo;
334 : proxy_session_t *ps;
335 :
336 0 : ASSERT (s->thread_index == thread_index);
337 :
338 0 : clib_spinlock_lock_if_init (&pm->sessions_lock);
339 :
340 0 : ps = proxy_session_get (s->opaque);
341 :
342 0 : if (PREDICT_TRUE (ps->vpp_active_open_handle != SESSION_INVALID_HANDLE))
343 : {
344 0 : clib_spinlock_unlock_if_init (&pm->sessions_lock);
345 :
346 0 : ao_tx_fifo = s->rx_fifo;
347 :
348 : /*
349 : * Send event for active open tx fifo
350 : */
351 0 : if (svm_fifo_set_event (ao_tx_fifo))
352 : {
353 0 : u32 ao_thread_index = ao_tx_fifo->master_thread_index;
354 0 : u32 ao_session_index = ao_tx_fifo->shr->master_session_index;
355 0 : if (session_send_io_evt_to_thread_custom (&ao_session_index,
356 : ao_thread_index,
357 : SESSION_IO_EVT_TX))
358 0 : clib_warning ("failed to enqueue tx evt");
359 : }
360 :
361 0 : if (svm_fifo_max_enqueue (ao_tx_fifo) <= TCP_MSS)
362 0 : svm_fifo_add_want_deq_ntf (ao_tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
363 : }
364 : else
365 : {
366 0 : vnet_connect_args_t _a, *a = &_a;
367 : svm_fifo_t *tx_fifo, *rx_fifo;
368 : u32 max_dequeue, ps_index;
369 : int actual_transfer __attribute__ ((unused));
370 :
371 0 : rx_fifo = s->rx_fifo;
372 0 : tx_fifo = s->tx_fifo;
373 :
374 0 : ASSERT (rx_fifo->master_thread_index == thread_index);
375 0 : ASSERT (tx_fifo->master_thread_index == thread_index);
376 :
377 0 : max_dequeue = svm_fifo_max_dequeue_cons (s->rx_fifo);
378 :
379 0 : if (PREDICT_FALSE (max_dequeue == 0))
380 : {
381 0 : clib_spinlock_unlock_if_init (&pm->sessions_lock);
382 0 : return 0;
383 : }
384 :
385 0 : max_dequeue = clib_min (pm->rcv_buffer_size, max_dequeue);
386 0 : actual_transfer = svm_fifo_peek (rx_fifo, 0 /* relative_offset */ ,
387 0 : max_dequeue, pm->rx_buf[thread_index]);
388 :
389 : /* $$$ your message in this space: parse url, etc. */
390 :
391 0 : clib_memset (a, 0, sizeof (*a));
392 :
393 0 : ps->server_rx_fifo = rx_fifo;
394 0 : ps->server_tx_fifo = tx_fifo;
395 0 : ps->active_open_establishing = 1;
396 0 : ps_index = ps->ps_index;
397 :
398 0 : clib_spinlock_unlock_if_init (&pm->sessions_lock);
399 :
400 0 : clib_memcpy (&a->sep_ext, &pm->client_sep, sizeof (pm->client_sep));
401 0 : a->api_context = ps_index;
402 0 : a->app_index = pm->active_open_app_index;
403 :
404 0 : if (proxy_transport_needs_crypto (a->sep.transport_proto))
405 : {
406 0 : session_endpoint_alloc_ext_cfg (&a->sep_ext,
407 : TRANSPORT_ENDPT_EXT_CFG_CRYPTO);
408 0 : a->sep_ext.ext_cfg->crypto.ckpair_index = pm->ckpair_index;
409 : }
410 :
411 0 : proxy_call_main_thread (a);
412 : }
413 :
414 0 : return 0;
415 : }
416 :
417 : static void
418 0 : proxy_force_ack (void *handlep)
419 : {
420 : transport_connection_t *tc;
421 : session_t *ao_s;
422 :
423 0 : ao_s = session_get_from_handle (pointer_to_uword (handlep));
424 0 : if (session_get_transport_proto (ao_s) != TRANSPORT_PROTO_TCP)
425 0 : return;
426 0 : tc = session_get_transport (ao_s);
427 0 : tcp_send_ack ((tcp_connection_t *) tc);
428 : }
429 :
430 : static int
431 0 : proxy_tx_callback (session_t * proxy_s)
432 : {
433 0 : proxy_main_t *pm = &proxy_main;
434 : proxy_session_t *ps;
435 : u32 min_free;
436 :
437 0 : min_free = clib_min (svm_fifo_size (proxy_s->tx_fifo) >> 3, 128 << 10);
438 0 : if (svm_fifo_max_enqueue (proxy_s->tx_fifo) < min_free)
439 : {
440 0 : svm_fifo_add_want_deq_ntf (proxy_s->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
441 0 : return 0;
442 : }
443 :
444 0 : clib_spinlock_lock_if_init (&pm->sessions_lock);
445 :
446 0 : ps = proxy_session_get (proxy_s->opaque);
447 :
448 0 : if (ps->vpp_active_open_handle == SESSION_INVALID_HANDLE)
449 0 : goto unlock;
450 :
451 : /* Force ack on active open side to update rcv wnd. Make sure it's done on
452 : * the right thread */
453 0 : void *arg = uword_to_pointer (ps->vpp_active_open_handle, void *);
454 0 : session_send_rpc_evt_to_thread (ps->server_rx_fifo->master_thread_index,
455 : proxy_force_ack, arg);
456 :
457 0 : unlock:
458 0 : clib_spinlock_unlock_if_init (&pm->sessions_lock);
459 :
460 0 : return 0;
461 : }
462 :
463 : static void
464 0 : proxy_cleanup_callback (session_t * s, session_cleanup_ntf_t ntf)
465 : {
466 0 : if (ntf == SESSION_CLEANUP_TRANSPORT)
467 0 : return;
468 :
469 0 : proxy_try_delete_session (s, 0 /* is_active_open */ );
470 : }
471 :
472 : static session_cb_vft_t proxy_session_cb_vft = {
473 : .session_accept_callback = proxy_accept_callback,
474 : .session_disconnect_callback = proxy_disconnect_callback,
475 : .session_connected_callback = proxy_connected_callback,
476 : .add_segment_callback = proxy_add_segment_callback,
477 : .builtin_app_rx_callback = proxy_rx_callback,
478 : .builtin_app_tx_callback = proxy_tx_callback,
479 : .session_reset_callback = proxy_reset_callback,
480 : .session_cleanup_callback = proxy_cleanup_callback,
481 : .fifo_tuning_callback = common_fifo_tuning_callback
482 : };
483 :
484 : static int
485 0 : active_open_connected_callback (u32 app_index, u32 opaque,
486 : session_t * s, session_error_t err)
487 : {
488 0 : proxy_main_t *pm = &proxy_main;
489 : proxy_session_t *ps;
490 0 : u8 thread_index = vlib_get_thread_index ();
491 :
492 : /*
493 : * Setup proxy session handle.
494 : */
495 0 : clib_spinlock_lock_if_init (&pm->sessions_lock);
496 :
497 0 : ps = proxy_session_get (opaque);
498 :
499 : /* Connection failed */
500 0 : if (err)
501 : {
502 0 : vnet_disconnect_args_t _a, *a = &_a;
503 :
504 0 : a->handle = ps->vpp_server_handle;
505 0 : a->app_index = pm->server_app_index;
506 0 : vnet_disconnect_session (a);
507 0 : ps->po_disconnected = 1;
508 : }
509 : else
510 : {
511 0 : ps->vpp_active_open_handle = session_handle (s);
512 0 : ps->active_open_establishing = 0;
513 : }
514 :
515 : /* Passive open session was already closed! */
516 0 : if (ps->po_disconnected)
517 : {
518 : /* Setup everything for the cleanup notification */
519 0 : ps->ao_disconnected = 1;
520 0 : clib_spinlock_unlock_if_init (&pm->sessions_lock);
521 0 : return -1;
522 : }
523 :
524 0 : s->tx_fifo = ps->server_rx_fifo;
525 0 : s->rx_fifo = ps->server_tx_fifo;
526 :
527 : /*
528 : * Reset the active-open tx-fifo master indices so the active-open session
529 : * will receive data, etc.
530 : */
531 0 : s->tx_fifo->shr->master_session_index = s->session_index;
532 0 : s->tx_fifo->master_thread_index = s->thread_index;
533 :
534 : /*
535 : * Account for the active-open session's use of the fifos
536 : * so they won't disappear until the last session which uses
537 : * them disappears
538 : */
539 0 : s->tx_fifo->refcnt++;
540 0 : s->rx_fifo->refcnt++;
541 :
542 0 : s->opaque = opaque;
543 :
544 0 : clib_spinlock_unlock_if_init (&pm->sessions_lock);
545 :
546 : /*
547 : * Send event for active open tx fifo
548 : */
549 0 : ASSERT (s->thread_index == thread_index);
550 0 : if (svm_fifo_set_event (s->tx_fifo))
551 0 : session_send_io_evt_to_thread (s->tx_fifo, SESSION_IO_EVT_TX);
552 :
553 0 : return 0;
554 : }
555 :
556 : static void
557 0 : active_open_reset_callback (session_t * s)
558 : {
559 0 : proxy_try_close_session (s, 1 /* is_active_open */ );
560 0 : }
561 :
562 : static int
563 0 : active_open_create_callback (session_t * s)
564 : {
565 0 : return 0;
566 : }
567 :
568 : static void
569 0 : active_open_disconnect_callback (session_t * s)
570 : {
571 0 : proxy_try_close_session (s, 1 /* is_active_open */ );
572 0 : }
573 :
574 : static int
575 0 : active_open_rx_callback (session_t * s)
576 : {
577 : svm_fifo_t *proxy_tx_fifo;
578 :
579 0 : proxy_tx_fifo = s->rx_fifo;
580 :
581 : /*
582 : * Send event for server tx fifo
583 : */
584 0 : if (svm_fifo_set_event (proxy_tx_fifo))
585 : {
586 0 : u8 thread_index = proxy_tx_fifo->master_thread_index;
587 0 : u32 session_index = proxy_tx_fifo->shr->master_session_index;
588 0 : return session_send_io_evt_to_thread_custom (&session_index,
589 : thread_index,
590 : SESSION_IO_EVT_TX);
591 : }
592 :
593 0 : if (svm_fifo_max_enqueue (proxy_tx_fifo) <= TCP_MSS)
594 0 : svm_fifo_add_want_deq_ntf (proxy_tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
595 :
596 0 : return 0;
597 : }
598 :
599 : static int
600 0 : active_open_tx_callback (session_t * ao_s)
601 : {
602 0 : proxy_main_t *pm = &proxy_main;
603 : transport_connection_t *tc;
604 : proxy_session_t *ps;
605 : session_t *proxy_s;
606 : u32 min_free;
607 :
608 0 : min_free = clib_min (svm_fifo_size (ao_s->tx_fifo) >> 3, 128 << 10);
609 0 : if (svm_fifo_max_enqueue (ao_s->tx_fifo) < min_free)
610 : {
611 0 : svm_fifo_add_want_deq_ntf (ao_s->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
612 0 : return 0;
613 : }
614 :
615 0 : clib_spinlock_lock_if_init (&pm->sessions_lock);
616 :
617 0 : ps = proxy_session_get_if_valid (ao_s->opaque);
618 0 : if (!ps)
619 0 : goto unlock;
620 :
621 0 : if (ps->vpp_server_handle == ~0)
622 0 : goto unlock;
623 :
624 0 : proxy_s = session_get_from_handle (ps->vpp_server_handle);
625 :
626 : /* Force ack on proxy side to update rcv wnd */
627 0 : tc = session_get_transport (proxy_s);
628 0 : tcp_send_ack ((tcp_connection_t *) tc);
629 :
630 0 : unlock:
631 0 : clib_spinlock_unlock_if_init (&pm->sessions_lock);
632 :
633 0 : return 0;
634 : }
635 :
636 : static void
637 0 : active_open_cleanup_callback (session_t * s, session_cleanup_ntf_t ntf)
638 : {
639 0 : if (ntf == SESSION_CLEANUP_TRANSPORT)
640 0 : return;
641 :
642 0 : proxy_try_delete_session (s, 1 /* is_active_open */ );
643 : }
644 :
645 : /* *INDENT-OFF* */
646 : static session_cb_vft_t active_open_clients = {
647 : .session_reset_callback = active_open_reset_callback,
648 : .session_connected_callback = active_open_connected_callback,
649 : .session_accept_callback = active_open_create_callback,
650 : .session_disconnect_callback = active_open_disconnect_callback,
651 : .session_cleanup_callback = active_open_cleanup_callback,
652 : .builtin_app_rx_callback = active_open_rx_callback,
653 : .builtin_app_tx_callback = active_open_tx_callback,
654 : .fifo_tuning_callback = common_fifo_tuning_callback
655 : };
656 : /* *INDENT-ON* */
657 :
658 : static int
659 0 : proxy_server_attach ()
660 : {
661 0 : proxy_main_t *pm = &proxy_main;
662 : u64 options[APP_OPTIONS_N_OPTIONS];
663 0 : vnet_app_attach_args_t _a, *a = &_a;
664 :
665 0 : clib_memset (a, 0, sizeof (*a));
666 0 : clib_memset (options, 0, sizeof (options));
667 :
668 0 : a->name = format (0, "proxy-server");
669 0 : a->api_client_index = pm->server_client_index;
670 0 : a->session_cb_vft = &proxy_session_cb_vft;
671 0 : a->options = options;
672 0 : a->options[APP_OPTIONS_SEGMENT_SIZE] = pm->segment_size;
673 0 : a->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = pm->segment_size;
674 0 : a->options[APP_OPTIONS_RX_FIFO_SIZE] = pm->fifo_size;
675 0 : a->options[APP_OPTIONS_TX_FIFO_SIZE] = pm->fifo_size;
676 0 : a->options[APP_OPTIONS_MAX_FIFO_SIZE] = pm->max_fifo_size;
677 0 : a->options[APP_OPTIONS_HIGH_WATERMARK] = (u64) pm->high_watermark;
678 0 : a->options[APP_OPTIONS_LOW_WATERMARK] = (u64) pm->low_watermark;
679 0 : a->options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = pm->private_segment_count;
680 0 : a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
681 0 : pm->prealloc_fifos ? pm->prealloc_fifos : 0;
682 :
683 0 : a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
684 :
685 0 : if (vnet_application_attach (a))
686 : {
687 0 : clib_warning ("failed to attach server");
688 0 : return -1;
689 : }
690 0 : pm->server_app_index = a->app_index;
691 :
692 0 : vec_free (a->name);
693 0 : return 0;
694 : }
695 :
696 : static int
697 0 : active_open_attach (void)
698 : {
699 0 : proxy_main_t *pm = &proxy_main;
700 0 : vnet_app_attach_args_t _a, *a = &_a;
701 : u64 options[APP_OPTIONS_N_OPTIONS];
702 :
703 0 : clib_memset (a, 0, sizeof (*a));
704 0 : clib_memset (options, 0, sizeof (options));
705 :
706 0 : a->api_client_index = pm->active_open_client_index;
707 0 : a->session_cb_vft = &active_open_clients;
708 0 : a->name = format (0, "proxy-active-open");
709 :
710 0 : options[APP_OPTIONS_ACCEPT_COOKIE] = 0x12345678;
711 0 : options[APP_OPTIONS_SEGMENT_SIZE] = 512 << 20;
712 0 : options[APP_OPTIONS_RX_FIFO_SIZE] = pm->fifo_size;
713 0 : options[APP_OPTIONS_TX_FIFO_SIZE] = pm->fifo_size;
714 0 : options[APP_OPTIONS_MAX_FIFO_SIZE] = pm->max_fifo_size;
715 0 : options[APP_OPTIONS_HIGH_WATERMARK] = (u64) pm->high_watermark;
716 0 : options[APP_OPTIONS_LOW_WATERMARK] = (u64) pm->low_watermark;
717 0 : options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = pm->private_segment_count;
718 0 : options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
719 0 : pm->prealloc_fifos ? pm->prealloc_fifos : 0;
720 :
721 0 : options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN
722 : | APP_OPTIONS_FLAGS_IS_PROXY;
723 :
724 0 : a->options = options;
725 :
726 0 : if (vnet_application_attach (a))
727 0 : return -1;
728 :
729 0 : pm->active_open_app_index = a->app_index;
730 :
731 0 : vec_free (a->name);
732 :
733 0 : return 0;
734 : }
735 :
736 : static int
737 0 : proxy_server_listen ()
738 : {
739 0 : proxy_main_t *pm = &proxy_main;
740 0 : vnet_listen_args_t _a, *a = &_a;
741 : int rv;
742 :
743 0 : clib_memset (a, 0, sizeof (*a));
744 :
745 0 : a->app_index = pm->server_app_index;
746 0 : clib_memcpy (&a->sep_ext, &pm->server_sep, sizeof (pm->server_sep));
747 0 : if (proxy_transport_needs_crypto (a->sep.transport_proto))
748 : {
749 0 : session_endpoint_alloc_ext_cfg (&a->sep_ext,
750 : TRANSPORT_ENDPT_EXT_CFG_CRYPTO);
751 0 : a->sep_ext.ext_cfg->crypto.ckpair_index = pm->ckpair_index;
752 : }
753 :
754 0 : rv = vnet_listen (a);
755 0 : if (a->sep_ext.ext_cfg)
756 0 : clib_mem_free (a->sep_ext.ext_cfg);
757 :
758 0 : return rv;
759 : }
760 :
761 : static void
762 0 : proxy_server_add_ckpair (void)
763 : {
764 0 : vnet_app_add_cert_key_pair_args_t _ck_pair, *ck_pair = &_ck_pair;
765 0 : proxy_main_t *pm = &proxy_main;
766 :
767 0 : clib_memset (ck_pair, 0, sizeof (*ck_pair));
768 0 : ck_pair->cert = (u8 *) test_srv_crt_rsa;
769 0 : ck_pair->key = (u8 *) test_srv_key_rsa;
770 0 : ck_pair->cert_len = test_srv_crt_rsa_len;
771 0 : ck_pair->key_len = test_srv_key_rsa_len;
772 0 : vnet_app_add_cert_key_pair (ck_pair);
773 :
774 0 : pm->ckpair_index = ck_pair->index;
775 0 : }
776 :
777 : static int
778 0 : proxy_server_create (vlib_main_t * vm)
779 : {
780 0 : vlib_thread_main_t *vtm = vlib_get_thread_main ();
781 0 : proxy_main_t *pm = &proxy_main;
782 : u32 num_threads;
783 : int i;
784 :
785 0 : num_threads = 1 /* main thread */ + vtm->n_threads;
786 0 : vec_validate (pm->rx_buf, num_threads - 1);
787 :
788 0 : for (i = 0; i < num_threads; i++)
789 0 : vec_validate (pm->rx_buf[i], pm->rcv_buffer_size);
790 :
791 0 : proxy_server_add_ckpair ();
792 :
793 0 : if (proxy_server_attach ())
794 : {
795 0 : clib_warning ("failed to attach server app");
796 0 : return -1;
797 : }
798 0 : if (proxy_server_listen ())
799 : {
800 0 : clib_warning ("failed to start listening");
801 0 : return -1;
802 : }
803 0 : if (active_open_attach ())
804 : {
805 0 : clib_warning ("failed to attach active open app");
806 0 : return -1;
807 : }
808 :
809 0 : return 0;
810 : }
811 :
812 : static clib_error_t *
813 0 : proxy_server_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
814 : vlib_cli_command_t * cmd)
815 : {
816 0 : unformat_input_t _line_input, *line_input = &_line_input;
817 0 : char *default_server_uri = "tcp://0.0.0.0/23";
818 0 : char *default_client_uri = "tcp://6.0.2.2/23";
819 0 : u8 *server_uri = 0, *client_uri = 0;
820 0 : proxy_main_t *pm = &proxy_main;
821 0 : clib_error_t *error = 0;
822 : int rv, tmp32;
823 : u64 tmp64;
824 :
825 0 : pm->fifo_size = 64 << 10;
826 0 : pm->max_fifo_size = 128 << 20;
827 0 : pm->high_watermark = 80;
828 0 : pm->low_watermark = 50;
829 0 : pm->rcv_buffer_size = 1024;
830 0 : pm->prealloc_fifos = 0;
831 0 : pm->private_segment_count = 0;
832 0 : pm->segment_size = 512 << 20;
833 :
834 0 : if (vlib_num_workers ())
835 0 : clib_spinlock_init (&pm->sessions_lock);
836 :
837 0 : if (!unformat_user (input, unformat_line_input, line_input))
838 0 : return 0;
839 :
840 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
841 : {
842 0 : if (unformat (line_input, "fifo-size %U", unformat_memory_size,
843 : &pm->fifo_size))
844 : ;
845 0 : else if (unformat (line_input, "max-fifo-size %U", unformat_memory_size,
846 : &pm->max_fifo_size))
847 : ;
848 0 : else if (unformat (line_input, "high-watermark %d", &tmp32))
849 0 : pm->high_watermark = (u8) tmp32;
850 0 : else if (unformat (line_input, "low-watermark %d", &tmp32))
851 0 : pm->low_watermark = (u8) tmp32;
852 0 : else if (unformat (line_input, "rcv-buf-size %d", &pm->rcv_buffer_size))
853 : ;
854 0 : else if (unformat (line_input, "prealloc-fifos %d", &pm->prealloc_fifos))
855 : ;
856 0 : else if (unformat (line_input, "private-segment-count %d",
857 : &pm->private_segment_count))
858 : ;
859 0 : else if (unformat (line_input, "private-segment-size %U",
860 : unformat_memory_size, &tmp64))
861 : {
862 0 : pm->segment_size = tmp64;
863 : }
864 0 : else if (unformat (line_input, "server-uri %s", &server_uri))
865 0 : vec_add1 (server_uri, 0);
866 0 : else if (unformat (line_input, "client-uri %s", &client_uri))
867 0 : vec_add1 (client_uri, 0);
868 : else
869 : {
870 0 : error = clib_error_return (0, "unknown input `%U'",
871 : format_unformat_error, line_input);
872 0 : goto done;
873 : }
874 : }
875 :
876 0 : if (!server_uri)
877 : {
878 0 : clib_warning ("No server-uri provided, Using default: %s",
879 : default_server_uri);
880 0 : server_uri = format (0, "%s%c", default_server_uri, 0);
881 : }
882 0 : if (!client_uri)
883 : {
884 0 : clib_warning ("No client-uri provided, Using default: %s",
885 : default_client_uri);
886 0 : client_uri = format (0, "%s%c", default_client_uri, 0);
887 : }
888 :
889 0 : if (parse_uri ((char *) server_uri, &pm->server_sep))
890 : {
891 0 : error = clib_error_return (0, "Invalid server uri %v", server_uri);
892 0 : goto done;
893 : }
894 0 : if (parse_uri ((char *) client_uri, &pm->client_sep))
895 : {
896 0 : error = clib_error_return (0, "Invalid client uri %v", client_uri);
897 0 : goto done;
898 : }
899 :
900 0 : vnet_session_enable_disable (vm, 1 /* turn on session and transport */ );
901 :
902 0 : rv = proxy_server_create (vm);
903 0 : switch (rv)
904 : {
905 0 : case 0:
906 0 : break;
907 0 : default:
908 0 : error = clib_error_return (0, "server_create returned %d", rv);
909 : }
910 :
911 0 : done:
912 0 : unformat_free (line_input);
913 0 : vec_free (client_uri);
914 0 : vec_free (server_uri);
915 0 : return error;
916 : }
917 :
918 203447 : VLIB_CLI_COMMAND (proxy_create_command, static) =
919 : {
920 : .path = "test proxy server",
921 : .short_help = "test proxy server [server-uri <tcp://ip/port>]"
922 : "[client-uri <tcp://ip/port>][fifo-size <nn>[k|m]]"
923 : "[max-fifo-size <nn>[k|m]][high-watermark <nn>]"
924 : "[low-watermark <nn>][rcv-buf-size <nn>][prealloc-fifos <nn>]"
925 : "[private-segment-size <mem>][private-segment-count <nn>]",
926 : .function = proxy_server_create_command_fn,
927 : };
928 :
929 : clib_error_t *
930 559 : proxy_main_init (vlib_main_t * vm)
931 : {
932 559 : proxy_main_t *pm = &proxy_main;
933 559 : pm->server_client_index = ~0;
934 559 : pm->active_open_client_index = ~0;
935 :
936 559 : return 0;
937 : }
938 :
939 3359 : VLIB_INIT_FUNCTION (proxy_main_init);
940 :
941 : /*
942 : * fd.io coding-style-patch-verification: ON
943 : *
944 : * Local Variables:
945 : * eval: (c-set-style "gnu")
946 : * End:
947 : */
|