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/application_namespace.h>
19 : #include <vnet/session/application_local.h>
20 : #include <vnet/session/session.h>
21 :
22 : static app_main_t app_main;
23 :
24 : #define app_interface_check_thread_and_barrier(_fn, _arg) \
25 : if (PREDICT_FALSE (!vlib_thread_is_main_w_barrier ())) \
26 : { \
27 : vlib_rpc_call_main_thread (_fn, (u8 *) _arg, sizeof(*_arg)); \
28 : return 0; \
29 : }
30 :
31 : static app_listener_t *
32 73 : app_listener_alloc (application_t * app)
33 : {
34 : app_listener_t *app_listener;
35 73 : pool_get (app->listeners, app_listener);
36 73 : clib_memset (app_listener, 0, sizeof (*app_listener));
37 73 : app_listener->al_index = app_listener - app->listeners;
38 73 : app_listener->app_index = app->app_index;
39 73 : app_listener->session_index = SESSION_INVALID_INDEX;
40 73 : app_listener->local_index = SESSION_INVALID_INDEX;
41 73 : app_listener->ls_handle = SESSION_INVALID_HANDLE;
42 73 : return app_listener;
43 : }
44 :
45 : app_listener_t *
46 470 : app_listener_get (application_t * app, u32 app_listener_index)
47 : {
48 470 : return pool_elt_at_index (app->listeners, app_listener_index);
49 : }
50 :
51 : static void
52 57 : app_listener_free (application_t * app, app_listener_t * app_listener)
53 : {
54 57 : clib_bitmap_free (app_listener->workers);
55 : if (CLIB_DEBUG)
56 57 : clib_memset (app_listener, 0xfa, sizeof (*app_listener));
57 57 : pool_put (app->listeners, app_listener);
58 57 : }
59 :
60 : session_handle_t
61 71 : app_listener_handle (app_listener_t * al)
62 : {
63 71 : return al->ls_handle;
64 : }
65 :
66 : app_listener_t *
67 205 : app_listener_get_w_session (session_t * ls)
68 : {
69 : application_t *app;
70 :
71 205 : app = application_get_if_valid (ls->app_index);
72 205 : if (!app)
73 2 : return 0;
74 203 : return app_listener_get (app, ls->al_index);
75 : }
76 :
77 : session_handle_t
78 73 : app_listen_session_handle (session_t * ls)
79 : {
80 : app_listener_t *al;
81 73 : al = app_listener_get_w_session (ls);
82 73 : if (!al)
83 2 : return listen_session_get_handle (ls);
84 71 : return al->ls_handle;
85 : }
86 :
87 : app_listener_t *
88 119 : app_listener_get_w_handle (session_handle_t handle)
89 : {
90 : session_t *ls;
91 119 : ls = session_get_from_handle_if_valid (handle);
92 119 : if (!ls)
93 2 : return 0;
94 117 : return app_listener_get_w_session (ls);
95 : }
96 :
97 : app_listener_t *
98 73 : app_listener_lookup (application_t * app, session_endpoint_cfg_t * sep_ext)
99 : {
100 : u32 table_index, fib_proto;
101 : session_endpoint_t *sep;
102 : session_handle_t handle;
103 : session_t *ls;
104 : void *iface_ip;
105 : ip46_address_t original_ip;
106 :
107 73 : sep = (session_endpoint_t *) sep_ext;
108 73 : if (application_has_local_scope (app) && session_endpoint_is_local (sep))
109 : {
110 20 : table_index = application_local_session_table (app);
111 20 : handle = session_lookup_endpoint_listener (table_index, sep, 1);
112 20 : if (handle != SESSION_INVALID_HANDLE)
113 : {
114 2 : ls = listen_session_get_from_handle (handle);
115 2 : return app_listener_get_w_session (ls);
116 : }
117 : }
118 :
119 71 : fib_proto = session_endpoint_fib_proto (sep);
120 71 : table_index = session_lookup_get_index_for_fib (fib_proto, sep->fib_index);
121 71 : handle = session_lookup_endpoint_listener (table_index, sep, 1);
122 71 : if (handle != SESSION_INVALID_HANDLE)
123 : {
124 0 : ls = listen_session_get_from_handle (handle);
125 0 : return app_listener_get_w_session ((session_t *) ls);
126 : }
127 :
128 : /*
129 : * When binds to "inaddr_any", we add zero address in the local lookup table
130 : * and interface address in the global lookup table. If local scope disable,
131 : * the latter is the only clue to find the listener.
132 : */
133 124 : if (!application_has_local_scope (app) &&
134 53 : ip_is_zero (&sep_ext->ip, sep_ext->is_ip4) &&
135 40 : sep_ext->sw_if_index != ENDPOINT_INVALID_INDEX)
136 : {
137 33 : if ((iface_ip = ip_interface_get_first_ip (sep_ext->sw_if_index,
138 33 : sep_ext->is_ip4)))
139 : {
140 33 : ip_copy (&original_ip, &sep_ext->ip, sep_ext->is_ip4);
141 33 : ip_set (&sep_ext->ip, iface_ip, sep_ext->is_ip4);
142 33 : handle = session_lookup_endpoint_listener (table_index, sep, 1);
143 33 : ip_copy (&sep_ext->ip, &original_ip, sep_ext->is_ip4);
144 33 : if (handle != SESSION_INVALID_HANDLE)
145 : {
146 0 : ls = listen_session_get_from_handle (handle);
147 0 : return app_listener_get_w_session ((session_t *) ls);
148 : }
149 : }
150 : }
151 :
152 71 : return 0;
153 : }
154 :
155 : int
156 73 : app_listener_alloc_and_init (application_t * app,
157 : session_endpoint_cfg_t * sep,
158 : app_listener_t ** listener)
159 : {
160 : app_listener_t *app_listener;
161 : transport_connection_t *tc;
162 : u32 al_index, table_index;
163 : session_handle_t lh;
164 : session_type_t st;
165 73 : session_t *ls = 0;
166 : int rv;
167 :
168 73 : app_listener = app_listener_alloc (app);
169 73 : al_index = app_listener->al_index;
170 73 : st = session_type_from_proto_and_ip (sep->transport_proto, sep->is_ip4);
171 :
172 : /*
173 : * Add session endpoint to local session table. Only binds to "inaddr_any"
174 : * (i.e., zero address) are added to local scope table.
175 : */
176 73 : if (application_has_local_scope (app)
177 18 : && session_endpoint_is_local ((session_endpoint_t *) sep))
178 : {
179 : session_type_t local_st;
180 :
181 18 : local_st = session_type_from_proto_and_ip (TRANSPORT_PROTO_NONE,
182 18 : sep->is_ip4);
183 18 : ls = listen_session_alloc (0, local_st);
184 18 : ls->app_index = app->app_index;
185 18 : ls->app_wrk_index = sep->app_wrk_index;
186 18 : lh = session_handle (ls);
187 :
188 18 : if ((rv = session_listen (ls, sep)))
189 : {
190 0 : ls = session_get_from_handle (lh);
191 0 : session_free (ls);
192 0 : app_listener_free (app, app_listener);
193 0 : return rv;
194 : }
195 :
196 18 : ls = session_get_from_handle (lh);
197 18 : app_listener = app_listener_get (app, al_index);
198 18 : app_listener->local_index = ls->session_index;
199 18 : app_listener->ls_handle = lh;
200 18 : ls->al_index = al_index;
201 :
202 18 : table_index = application_local_session_table (app);
203 18 : session_lookup_add_session_endpoint (table_index,
204 : (session_endpoint_t *) sep, lh);
205 : }
206 :
207 73 : if (application_has_global_scope (app))
208 : {
209 : /*
210 : * Start listening on local endpoint for requested transport and scope.
211 : * Creates a stream session with state LISTENING to be used in session
212 : * lookups, prior to establishing connection. Requests transport to
213 : * build it's own specific listening connection.
214 : */
215 60 : ls = listen_session_alloc (0, st);
216 60 : ls->app_index = app->app_index;
217 60 : ls->app_wrk_index = sep->app_wrk_index;
218 :
219 : /* Listen pool can be reallocated if the transport is
220 : * recursive (tls) */
221 60 : lh = listen_session_get_handle (ls);
222 :
223 60 : if ((rv = session_listen (ls, sep)))
224 : {
225 0 : ls = listen_session_get_from_handle (lh);
226 0 : session_free (ls);
227 0 : app_listener_free (app, app_listener);
228 0 : return rv;
229 : }
230 60 : ls = listen_session_get_from_handle (lh);
231 60 : app_listener = app_listener_get (app, al_index);
232 60 : app_listener->session_index = ls->session_index;
233 60 : app_listener->ls_handle = lh;
234 60 : ls->al_index = al_index;
235 :
236 : /* Add to the global lookup table after transport was initialized.
237 : * Lookup table needs to be populated only now because sessions
238 : * with cut-through transport are are added to app local tables that
239 : * are not related to network fibs, i.e., cannot be added as
240 : * connections */
241 60 : tc = session_get_transport (ls);
242 60 : if (!(tc->flags & TRANSPORT_CONNECTION_F_NO_LOOKUP))
243 : {
244 : fib_protocol_t fib_proto;
245 54 : fib_proto = session_endpoint_fib_proto ((session_endpoint_t *) sep);
246 : /* Assume namespace vetted previously so make sure table exists */
247 54 : table_index = session_lookup_get_or_alloc_index_for_fib (
248 : fib_proto, sep->fib_index);
249 54 : session_lookup_add_session_endpoint (table_index,
250 : (session_endpoint_t *) sep,
251 : lh);
252 : }
253 : }
254 :
255 73 : if (!ls)
256 : {
257 0 : app_listener_free (app, app_listener);
258 0 : return -1;
259 : }
260 :
261 73 : *listener = app_listener;
262 73 : return 0;
263 : }
264 :
265 : void
266 57 : app_listener_cleanup (app_listener_t * al)
267 : {
268 57 : application_t *app = application_get (al->app_index);
269 : session_t *ls;
270 :
271 57 : if (al->session_index != SESSION_INVALID_INDEX)
272 : {
273 44 : ls = session_get (al->session_index, 0);
274 44 : session_stop_listen (ls);
275 44 : listen_session_free (ls);
276 : }
277 57 : if (al->local_index != SESSION_INVALID_INDEX)
278 : {
279 18 : session_endpoint_t sep = SESSION_ENDPOINT_NULL;
280 : u32 table_index;
281 :
282 18 : table_index = application_local_session_table (app);
283 18 : ls = listen_session_get (al->local_index);
284 18 : ct_session_endpoint (ls, &sep);
285 18 : session_lookup_del_session_endpoint (table_index, &sep);
286 18 : session_stop_listen (ls);
287 18 : listen_session_free (ls);
288 : }
289 57 : app_listener_free (app, al);
290 57 : }
291 :
292 : static app_worker_t *
293 189 : app_listener_select_worker (application_t * app, app_listener_t * al)
294 : {
295 : u32 wrk_index;
296 :
297 189 : app = application_get (al->app_index);
298 189 : wrk_index = clib_bitmap_next_set (al->workers, al->accept_rotor + 1);
299 189 : if (wrk_index == ~0)
300 189 : wrk_index = clib_bitmap_first_set (al->workers);
301 :
302 189 : ASSERT (wrk_index != ~0);
303 189 : al->accept_rotor = wrk_index;
304 189 : return application_get_worker (app, wrk_index);
305 : }
306 :
307 : session_t *
308 48 : app_listener_get_session (app_listener_t * al)
309 : {
310 48 : if (al->session_index == SESSION_INVALID_INDEX)
311 0 : return 0;
312 :
313 48 : return listen_session_get (al->session_index);
314 : }
315 :
316 : session_t *
317 12 : app_listener_get_local_session (app_listener_t * al)
318 : {
319 12 : if (al->local_index == SESSION_INVALID_INDEX)
320 0 : return 0;
321 12 : return listen_session_get (al->local_index);
322 : }
323 :
324 : static app_worker_map_t *
325 216 : app_worker_map_alloc (application_t * app)
326 : {
327 : app_worker_map_t *map;
328 216 : pool_get (app->worker_maps, map);
329 216 : clib_memset (map, 0, sizeof (*map));
330 216 : return map;
331 : }
332 :
333 : static u32
334 216 : app_worker_map_index (application_t * app, app_worker_map_t * map)
335 : {
336 216 : return (map - app->worker_maps);
337 : }
338 :
339 : static void
340 43 : app_worker_map_free (application_t * app, app_worker_map_t * map)
341 : {
342 43 : pool_put (app->worker_maps, map);
343 43 : }
344 :
345 : static app_worker_map_t *
346 669 : app_worker_map_get (application_t * app, u32 map_index)
347 : {
348 669 : if (pool_is_free_index (app->worker_maps, map_index))
349 0 : return 0;
350 669 : return pool_elt_at_index (app->worker_maps, map_index);
351 : }
352 :
353 : static const u8 *
354 0 : app_get_name (application_t * app)
355 : {
356 0 : return app->name;
357 : }
358 :
359 : u32
360 4 : application_session_table (application_t * app, u8 fib_proto)
361 : {
362 : app_namespace_t *app_ns;
363 4 : app_ns = app_namespace_get (app->ns_index);
364 4 : if (!application_has_global_scope (app))
365 1 : return APP_INVALID_INDEX;
366 3 : if (fib_proto == FIB_PROTOCOL_IP4)
367 3 : return session_lookup_get_index_for_fib (fib_proto,
368 : app_ns->ip4_fib_index);
369 : else
370 0 : return session_lookup_get_index_for_fib (fib_proto,
371 : app_ns->ip6_fib_index);
372 : }
373 :
374 : u32
375 77 : application_local_session_table (application_t * app)
376 : {
377 : app_namespace_t *app_ns;
378 77 : if (!application_has_local_scope (app))
379 1 : return APP_INVALID_INDEX;
380 76 : app_ns = app_namespace_get (app->ns_index);
381 76 : return app_ns->local_table_index;
382 : }
383 :
384 : /**
385 : * Returns app name for app-index
386 : */
387 : const u8 *
388 0 : application_name_from_index (u32 app_index)
389 : {
390 0 : application_t *app = application_get (app_index);
391 0 : if (!app)
392 0 : return 0;
393 0 : return app_get_name (app);
394 : }
395 :
396 : static void
397 57 : application_api_table_add (u32 app_index, u32 api_client_index)
398 : {
399 57 : if (api_client_index != APP_INVALID_INDEX)
400 57 : hash_set (app_main.app_by_api_client_index, api_client_index, app_index);
401 57 : }
402 :
403 : static void
404 43 : application_api_table_del (u32 api_client_index)
405 : {
406 43 : hash_unset (app_main.app_by_api_client_index, api_client_index);
407 43 : }
408 :
409 : static void
410 159 : application_name_table_add (application_t * app)
411 : {
412 318 : hash_set_mem (app_main.app_by_name, app->name, app->app_index);
413 159 : }
414 :
415 : static void
416 43 : application_name_table_del (application_t * app)
417 : {
418 86 : hash_unset_mem (app_main.app_by_name, app->name);
419 43 : }
420 :
421 : application_t *
422 1526 : application_lookup (u32 api_client_index)
423 : {
424 : uword *p;
425 1526 : p = hash_get (app_main.app_by_api_client_index, api_client_index);
426 1526 : if (p)
427 223 : return application_get_if_valid (p[0]);
428 :
429 1303 : return 0;
430 : }
431 :
432 : application_t *
433 160 : application_lookup_name (const u8 * name)
434 : {
435 : uword *p;
436 160 : p = hash_get_mem (app_main.app_by_name, name);
437 160 : if (p)
438 0 : return application_get (p[0]);
439 :
440 160 : return 0;
441 : }
442 :
443 : void
444 26 : appsl_pending_rx_mqs_add_tail (appsl_wrk_t *aw, app_rx_mq_elt_t *elt)
445 : {
446 : app_rx_mq_elt_t *head;
447 :
448 26 : if (!aw->pending_rx_mqs)
449 : {
450 23 : elt->next = elt->prev = elt;
451 23 : aw->pending_rx_mqs = elt;
452 23 : return;
453 : }
454 :
455 3 : head = aw->pending_rx_mqs;
456 :
457 3 : ASSERT (head != elt);
458 :
459 3 : elt->prev = head->prev;
460 3 : elt->next = head;
461 :
462 3 : head->prev->next = elt;
463 3 : head->prev = elt;
464 : }
465 :
466 : void
467 26 : appsl_pending_rx_mqs_del (appsl_wrk_t *aw, app_rx_mq_elt_t *elt)
468 : {
469 26 : if (elt->next == elt)
470 : {
471 23 : elt->next = elt->prev = 0;
472 23 : aw->pending_rx_mqs = 0;
473 23 : return;
474 : }
475 :
476 3 : if (elt == aw->pending_rx_mqs)
477 3 : aw->pending_rx_mqs = elt->next;
478 :
479 3 : elt->next->prev = elt->prev;
480 3 : elt->prev->next = elt->next;
481 3 : elt->next = elt->prev = 0;
482 : }
483 :
484 : vlib_node_registration_t appsl_rx_mqs_input_node;
485 :
486 601 : VLIB_NODE_FN (appsl_rx_mqs_input_node)
487 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
488 : {
489 26 : u32 thread_index = vm->thread_index, n_msgs = 0;
490 : app_rx_mq_elt_t *elt, *next;
491 26 : app_main_t *am = &app_main;
492 : session_worker_t *wrk;
493 : int __clib_unused rv;
494 : appsl_wrk_t *aw;
495 : u64 buf;
496 :
497 26 : aw = &am->wrk[thread_index];
498 26 : elt = aw->pending_rx_mqs;
499 26 : if (!elt)
500 2 : return 0;
501 :
502 24 : wrk = session_main_get_worker (thread_index);
503 :
504 : do
505 : {
506 24 : if (!(elt->flags & APP_RX_MQ_F_POSTPONED))
507 24 : rv = read (svm_msg_q_get_eventfd (elt->mq), &buf, sizeof (buf));
508 24 : n_msgs += session_wrk_handle_mq (wrk, elt->mq);
509 :
510 24 : next = elt->next;
511 24 : appsl_pending_rx_mqs_del (aw, elt);
512 24 : if (!svm_msg_q_is_empty (elt->mq))
513 : {
514 0 : elt->flags |= APP_RX_MQ_F_POSTPONED;
515 0 : appsl_pending_rx_mqs_add_tail (aw, elt);
516 : }
517 : else
518 : {
519 24 : elt->flags = 0;
520 : }
521 24 : elt = next;
522 : }
523 24 : while (aw->pending_rx_mqs && elt != aw->pending_rx_mqs);
524 :
525 24 : if (aw->pending_rx_mqs)
526 3 : vlib_node_set_interrupt_pending (vm, appsl_rx_mqs_input_node.index);
527 :
528 24 : if (n_msgs && wrk->state == SESSION_WRK_INTERRUPT)
529 20 : vlib_node_set_interrupt_pending (vm, session_queue_node.index);
530 :
531 24 : return n_msgs;
532 : }
533 :
534 183788 : VLIB_REGISTER_NODE (appsl_rx_mqs_input_node) = {
535 : .name = "appsl-rx-mqs-input",
536 : .type = VLIB_NODE_TYPE_INPUT,
537 : .state = VLIB_NODE_STATE_DISABLED,
538 : };
539 :
540 : static clib_error_t *
541 29 : app_rx_mq_fd_read_ready (clib_file_t *cf)
542 : {
543 29 : app_rx_mq_handle_t *handle = (app_rx_mq_handle_t *) &cf->private_data;
544 29 : vlib_main_t *vm = vlib_get_main ();
545 29 : app_main_t *am = &app_main;
546 : app_rx_mq_elt_t *mqe;
547 : application_t *app;
548 : appsl_wrk_t *aw;
549 :
550 29 : ASSERT (vlib_get_thread_index () == handle->thread_index);
551 29 : app = application_get_if_valid (handle->app_index);
552 29 : if (!app)
553 0 : return 0;
554 :
555 29 : mqe = &app->rx_mqs[handle->thread_index];
556 29 : if ((mqe->flags & APP_RX_MQ_F_PENDING) || svm_msg_q_is_empty (mqe->mq))
557 3 : return 0;
558 :
559 26 : aw = &am->wrk[handle->thread_index];
560 26 : appsl_pending_rx_mqs_add_tail (aw, mqe);
561 26 : mqe->flags |= APP_RX_MQ_F_PENDING;
562 :
563 26 : vlib_node_set_interrupt_pending (vm, appsl_rx_mqs_input_node.index);
564 :
565 26 : return 0;
566 : }
567 :
568 : static clib_error_t *
569 0 : app_rx_mq_fd_write_ready (clib_file_t *cf)
570 : {
571 0 : clib_warning ("should not be called");
572 0 : return 0;
573 : }
574 :
575 : static void
576 4 : app_rx_mqs_epoll_add (application_t *app, app_rx_mq_elt_t *mqe)
577 : {
578 4 : clib_file_t template = { 0 };
579 : app_rx_mq_handle_t handle;
580 : u32 thread_index;
581 : int fd;
582 :
583 4 : thread_index = mqe - app->rx_mqs;
584 4 : fd = svm_msg_q_get_eventfd (mqe->mq);
585 :
586 4 : handle.app_index = app->app_index;
587 4 : handle.thread_index = thread_index;
588 :
589 4 : template.read_function = app_rx_mq_fd_read_ready;
590 4 : template.write_function = app_rx_mq_fd_write_ready;
591 4 : template.file_descriptor = fd;
592 4 : template.private_data = handle.as_u64;
593 4 : template.polling_thread_index = thread_index;
594 4 : template.description =
595 4 : format (0, "app-%u-rx-mq-%u", app->app_index, thread_index);
596 4 : mqe->file_index = clib_file_add (&file_main, &template);
597 4 : }
598 :
599 : static void
600 4 : app_rx_mqs_epoll_del (application_t *app, app_rx_mq_elt_t *mqe)
601 : {
602 4 : u32 thread_index = mqe - app->rx_mqs;
603 4 : app_main_t *am = &app_main;
604 : appsl_wrk_t *aw;
605 :
606 4 : aw = &am->wrk[thread_index];
607 :
608 4 : session_wrk_handle_mq (session_main_get_worker (thread_index), mqe->mq);
609 :
610 4 : if (mqe->flags & APP_RX_MQ_F_PENDING)
611 2 : appsl_pending_rx_mqs_del (aw, mqe);
612 :
613 4 : clib_file_del_by_index (&file_main, mqe->file_index);
614 4 : }
615 :
616 : svm_msg_q_t *
617 4 : application_rx_mq_get (application_t *app, u32 mq_index)
618 : {
619 4 : if (!app->rx_mqs)
620 0 : return 0;
621 :
622 4 : return app->rx_mqs[mq_index].mq;
623 : }
624 :
625 : static int
626 4 : app_rx_mqs_alloc (application_t *app)
627 : {
628 4 : u32 evt_q_length, evt_size = sizeof (session_event_t);
629 4 : fifo_segment_t *eqs = &app->rx_mqs_segment;
630 4 : u32 n_mqs = vlib_num_workers () + 1;
631 : segment_manager_props_t *props;
632 : int i;
633 :
634 4 : props = application_segment_manager_properties (app);
635 4 : evt_q_length = clib_max (props->evt_q_size, 128);
636 :
637 4 : svm_msg_q_cfg_t _cfg, *cfg = &_cfg;
638 4 : svm_msg_q_ring_cfg_t rc[SESSION_MQ_N_RINGS] = {
639 4 : { evt_q_length, evt_size, 0 }, { evt_q_length >> 1, 256, 0 }
640 : };
641 4 : cfg->consumer_pid = 0;
642 4 : cfg->n_rings = 2;
643 4 : cfg->q_nitems = evt_q_length;
644 4 : cfg->ring_cfgs = rc;
645 :
646 4 : eqs->ssvm.ssvm_size = svm_msg_q_size_to_alloc (cfg) * n_mqs + (1 << 20);
647 4 : eqs->ssvm.name = format (0, "%v-rx-mqs-seg%c", app->name, 0);
648 :
649 4 : if (ssvm_server_init (&eqs->ssvm, SSVM_SEGMENT_MEMFD))
650 : {
651 0 : clib_warning ("failed to initialize queue segment");
652 0 : return SESSION_E_SEG_CREATE;
653 : }
654 :
655 4 : fifo_segment_init (eqs);
656 :
657 : /* Fifo segment filled only with mqs */
658 4 : eqs->h->n_mqs = n_mqs;
659 4 : vec_validate (app->rx_mqs, n_mqs - 1);
660 :
661 8 : for (i = 0; i < n_mqs; i++)
662 : {
663 4 : app->rx_mqs[i].mq = fifo_segment_msg_q_alloc (eqs, i, cfg);
664 4 : if (svm_msg_q_alloc_eventfd (app->rx_mqs[i].mq))
665 : {
666 0 : clib_warning ("eventfd returned");
667 0 : fifo_segment_cleanup (eqs);
668 0 : ssvm_delete (&eqs->ssvm);
669 0 : return SESSION_E_EVENTFD_ALLOC;
670 : }
671 4 : app_rx_mqs_epoll_add (app, &app->rx_mqs[i]);
672 4 : app->rx_mqs[i].app_index = app->app_index;
673 : }
674 :
675 4 : return 0;
676 : }
677 :
678 : u8
679 334 : application_use_private_rx_mqs (void)
680 : {
681 334 : return session_main.use_private_rx_mqs;
682 : }
683 :
684 : fifo_segment_t *
685 221 : application_get_rx_mqs_segment (application_t *app)
686 : {
687 221 : if (application_use_private_rx_mqs ())
688 18 : return &app->rx_mqs_segment;
689 203 : return session_main_get_wrk_mqs_segment ();
690 : }
691 :
692 : void
693 2 : application_enable_rx_mqs_nodes (u8 is_en)
694 : {
695 2 : u8 state = is_en ? VLIB_NODE_STATE_INTERRUPT : VLIB_NODE_STATE_DISABLED;
696 :
697 4 : foreach_vlib_main ()
698 2 : vlib_node_set_state (this_vlib_main, appsl_rx_mqs_input_node.index, state);
699 2 : }
700 :
701 : static application_t *
702 216 : application_alloc (void)
703 : {
704 : application_t *app;
705 216 : pool_get (app_main.app_pool, app);
706 216 : clib_memset (app, 0, sizeof (*app));
707 216 : app->app_index = app - app_main.app_pool;
708 216 : return app;
709 : }
710 :
711 : application_t *
712 219278 : application_get (u32 app_index)
713 : {
714 219278 : if (app_index == APP_INVALID_INDEX)
715 0 : return 0;
716 219278 : return pool_elt_at_index (app_main.app_pool, app_index);
717 : }
718 :
719 : application_t *
720 674 : application_get_if_valid (u32 app_index)
721 : {
722 674 : if (pool_is_free_index (app_main.app_pool, app_index))
723 2 : return 0;
724 :
725 672 : return pool_elt_at_index (app_main.app_pool, app_index);
726 : }
727 :
728 : static int
729 0 : _null_app_tx_callback (session_t *s)
730 : {
731 0 : return 0;
732 : }
733 :
734 : static void
735 216 : application_verify_cb_fns (session_cb_vft_t * cb_fns)
736 : {
737 216 : if (cb_fns->session_accept_callback == 0)
738 0 : clib_warning ("No accept callback function provided");
739 216 : if (cb_fns->session_connected_callback == 0)
740 0 : clib_warning ("No session connected callback function provided");
741 216 : if (cb_fns->session_disconnect_callback == 0)
742 0 : clib_warning ("No session disconnect callback function provided");
743 216 : if (cb_fns->session_reset_callback == 0)
744 0 : clib_warning ("No session reset callback function provided");
745 216 : if (!cb_fns->builtin_app_tx_callback)
746 39 : cb_fns->builtin_app_tx_callback = _null_app_tx_callback;
747 216 : }
748 :
749 : /**
750 : * Check app config for given segment type
751 : *
752 : * Returns 1 on success and 0 otherwise
753 : */
754 : static u8
755 216 : application_verify_cfg (ssvm_segment_type_t st)
756 : {
757 : u8 is_valid;
758 216 : if (st == SSVM_SEGMENT_MEMFD)
759 : {
760 57 : is_valid = (session_main_get_wrk_mqs_segment () != 0);
761 57 : if (!is_valid)
762 0 : clib_warning ("memfd seg: vpp's event qs IN binary api svm region");
763 57 : return is_valid;
764 : }
765 159 : else if (st == SSVM_SEGMENT_SHM)
766 : {
767 0 : is_valid = (session_main_get_wrk_mqs_segment () == 0);
768 0 : if (!is_valid)
769 0 : clib_warning ("shm seg: vpp's event qs NOT IN binary api svm region");
770 0 : return is_valid;
771 : }
772 : else
773 159 : return 1;
774 : }
775 :
776 : static session_error_t
777 216 : application_alloc_and_init (app_init_args_t *a)
778 : {
779 216 : ssvm_segment_type_t seg_type = SSVM_SEGMENT_MEMFD;
780 : segment_manager_props_t *props;
781 : application_t *app;
782 : u64 *opts;
783 :
784 216 : app = application_alloc ();
785 216 : opts = a->options;
786 : /*
787 : * Make sure we support the requested configuration
788 : */
789 216 : if ((opts[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_IS_BUILTIN) &&
790 159 : !(opts[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_MEMFD_FOR_BUILTIN))
791 159 : seg_type = SSVM_SEGMENT_PRIVATE;
792 :
793 216 : if ((opts[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD) &&
794 : seg_type != SSVM_SEGMENT_MEMFD)
795 : {
796 0 : clib_warning ("mq eventfds can only be used if socket transport is "
797 : "used for binary api");
798 0 : return SESSION_E_NOSUPPORT;
799 : }
800 :
801 216 : if (!application_verify_cfg (seg_type))
802 0 : return SESSION_E_NOSUPPORT;
803 :
804 216 : if (opts[APP_OPTIONS_PREALLOC_FIFO_PAIRS] &&
805 72 : opts[APP_OPTIONS_PREALLOC_FIFO_HDRS])
806 0 : return SESSION_E_NOSUPPORT;
807 :
808 : /* Check that the obvious things are properly set up */
809 216 : application_verify_cb_fns (a->session_cb_vft);
810 :
811 216 : app->flags = opts[APP_OPTIONS_FLAGS];
812 216 : app->cb_fns = *a->session_cb_vft;
813 216 : app->ns_index = opts[APP_OPTIONS_NAMESPACE];
814 216 : app->proxied_transports = opts[APP_OPTIONS_PROXY_TRANSPORT];
815 216 : app->name = vec_dup (a->name);
816 :
817 : /* If no scope enabled, default to global */
818 216 : if (!application_has_global_scope (app)
819 47 : && !application_has_local_scope (app))
820 28 : app->flags |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
821 :
822 216 : props = application_segment_manager_properties (app);
823 216 : segment_manager_props_init (props);
824 216 : props->segment_size = opts[APP_OPTIONS_SEGMENT_SIZE];
825 216 : props->prealloc_fifos = opts[APP_OPTIONS_PREALLOC_FIFO_PAIRS];
826 216 : props->prealloc_fifo_hdrs = opts[APP_OPTIONS_PREALLOC_FIFO_HDRS];
827 216 : if (opts[APP_OPTIONS_ADD_SEGMENT_SIZE])
828 : {
829 199 : props->add_segment_size = opts[APP_OPTIONS_ADD_SEGMENT_SIZE];
830 199 : props->add_segment = 1;
831 : }
832 216 : if (opts[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_USE_HUGE_PAGE)
833 0 : props->huge_page = 1;
834 216 : if (opts[APP_OPTIONS_RX_FIFO_SIZE])
835 202 : props->rx_fifo_size = opts[APP_OPTIONS_RX_FIFO_SIZE];
836 216 : if (opts[APP_OPTIONS_TX_FIFO_SIZE])
837 202 : props->tx_fifo_size = opts[APP_OPTIONS_TX_FIFO_SIZE];
838 216 : if (opts[APP_OPTIONS_EVT_QUEUE_SIZE])
839 57 : props->evt_q_size = opts[APP_OPTIONS_EVT_QUEUE_SIZE];
840 216 : if (opts[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
841 0 : props->use_mq_eventfd = 1;
842 216 : if (opts[APP_OPTIONS_TLS_ENGINE])
843 68 : app->tls_engine = opts[APP_OPTIONS_TLS_ENGINE];
844 216 : if (opts[APP_OPTIONS_MAX_FIFO_SIZE])
845 0 : props->max_fifo_size = opts[APP_OPTIONS_MAX_FIFO_SIZE];
846 216 : if (opts[APP_OPTIONS_HIGH_WATERMARK])
847 0 : props->high_watermark = opts[APP_OPTIONS_HIGH_WATERMARK];
848 216 : if (opts[APP_OPTIONS_LOW_WATERMARK])
849 0 : props->low_watermark = opts[APP_OPTIONS_LOW_WATERMARK];
850 216 : if (opts[APP_OPTIONS_PCT_FIRST_ALLOC])
851 16 : props->pct_first_alloc = opts[APP_OPTIONS_PCT_FIRST_ALLOC];
852 216 : props->segment_type = seg_type;
853 :
854 : /* Add app to lookup by api_client_index table */
855 216 : if (!application_is_builtin (app))
856 57 : application_api_table_add (app->app_index, a->api_client_index);
857 : else
858 159 : application_name_table_add (app);
859 :
860 216 : a->app_index = app->app_index;
861 :
862 : APP_DBG ("New app name: %v api index: %u index %u", app->name,
863 : a->api_client_index, app->app_index);
864 :
865 216 : return 0;
866 : }
867 :
868 : static void
869 87 : application_free (application_t * app)
870 : {
871 : app_worker_map_t *wrk_map;
872 : app_worker_t *app_wrk;
873 :
874 : /*
875 : * The app event queue allocated in first segment is cleared with
876 : * the segment manager. No need to explicitly free it.
877 : */
878 : APP_DBG ("Delete app name %v index: %d", app->name, app->app_index);
879 :
880 87 : if (application_is_proxy (app))
881 1 : application_remove_proxy (app);
882 :
883 : /*
884 : * Free workers
885 : */
886 :
887 : /* *INDENT-OFF* */
888 175 : pool_flush (wrk_map, app->worker_maps, ({
889 : app_wrk = app_worker_get (wrk_map->wrk_index);
890 : app_worker_free (app_wrk);
891 : }));
892 : /* *INDENT-ON* */
893 87 : pool_free (app->worker_maps);
894 :
895 : /*
896 : * Free rx mqs if allocated
897 : */
898 87 : if (app->rx_mqs)
899 : {
900 : int i;
901 8 : for (i = 0; i < vec_len (app->rx_mqs); i++)
902 4 : app_rx_mqs_epoll_del (app, &app->rx_mqs[i]);
903 :
904 4 : fifo_segment_cleanup (&app->rx_mqs_segment);
905 4 : ssvm_delete (&app->rx_mqs_segment.ssvm);
906 4 : vec_free (app->rx_mqs);
907 : }
908 :
909 : /*
910 : * Cleanup remaining state
911 : */
912 87 : if (application_is_builtin (app))
913 43 : application_name_table_del (app);
914 87 : vec_free (app->name);
915 87 : pool_put (app_main.app_pool, app);
916 87 : }
917 :
918 : static void
919 66 : application_detach_process (application_t * app, u32 api_client_index)
920 : {
921 66 : vnet_app_worker_add_del_args_t _args = { 0 }, *args = &_args;
922 : app_worker_map_t *wrk_map;
923 66 : u32 *wrks = 0, *wrk_index;
924 : app_worker_t *app_wrk;
925 :
926 66 : if (api_client_index == ~0)
927 : {
928 44 : application_free (app);
929 44 : return;
930 : }
931 :
932 : APP_DBG ("Detaching for app %v index %u api client index %u", app->name,
933 : app->app_index, api_client_index);
934 :
935 : /* *INDENT-OFF* */
936 44 : pool_foreach (wrk_map, app->worker_maps) {
937 22 : app_wrk = app_worker_get (wrk_map->wrk_index);
938 22 : if (app_wrk->api_client_index == api_client_index)
939 22 : vec_add1 (wrks, app_wrk->wrk_index);
940 : }
941 : /* *INDENT-ON* */
942 :
943 22 : if (!vec_len (wrks))
944 : {
945 0 : clib_warning ("no workers for app %u api_index %u", app->app_index,
946 : api_client_index);
947 0 : return;
948 : }
949 :
950 22 : args->app_index = app->app_index;
951 22 : args->api_client_index = api_client_index;
952 44 : vec_foreach (wrk_index, wrks)
953 : {
954 22 : app_wrk = app_worker_get (wrk_index[0]);
955 22 : args->wrk_map_index = app_wrk->wrk_map_index;
956 22 : args->is_add = 0;
957 22 : vnet_app_worker_add_del (args);
958 : }
959 22 : vec_free (wrks);
960 : }
961 :
962 : void
963 3 : application_namespace_cleanup (app_namespace_t *app_ns)
964 : {
965 3 : u32 *app_indices = 0, *app_index;
966 : application_t *app;
967 : u32 ns_index;
968 :
969 3 : ns_index = app_namespace_index (app_ns);
970 9 : pool_foreach (app, app_main.app_pool)
971 6 : if (app->ns_index == ns_index)
972 0 : vec_add1 (app_indices, app->ns_index);
973 :
974 3 : vec_foreach (app_index, app_indices)
975 : {
976 0 : app = application_get (*app_index);
977 :
978 0 : if (application_is_proxy (app))
979 0 : application_remove_proxy (app);
980 0 : app->flags &= ~APP_OPTIONS_FLAGS_IS_PROXY;
981 :
982 0 : application_free (app);
983 : }
984 3 : vec_free (app_indices);
985 3 : }
986 :
987 : app_worker_t *
988 626 : application_get_worker (application_t * app, u32 wrk_map_index)
989 : {
990 : app_worker_map_t *map;
991 626 : map = app_worker_map_get (app, wrk_map_index);
992 626 : if (!map)
993 0 : return 0;
994 626 : return app_worker_get (map->wrk_index);
995 : }
996 :
997 : app_worker_t *
998 13 : application_get_default_worker (application_t * app)
999 : {
1000 13 : return application_get_worker (app, 0);
1001 : }
1002 :
1003 : u32
1004 43 : application_n_workers (application_t * app)
1005 : {
1006 43 : return pool_elts (app->worker_maps);
1007 : }
1008 :
1009 : app_worker_t *
1010 189 : application_listener_select_worker (session_t * ls)
1011 : {
1012 : application_t *app;
1013 : app_listener_t *al;
1014 :
1015 189 : app = application_get (ls->app_index);
1016 189 : al = app_listener_get (app, ls->al_index);
1017 189 : return app_listener_select_worker (app, al);
1018 : }
1019 :
1020 : int
1021 216 : application_alloc_worker_and_init (application_t * app, app_worker_t ** wrk)
1022 : {
1023 : app_worker_map_t *wrk_map;
1024 : app_worker_t *app_wrk;
1025 : segment_manager_t *sm;
1026 : int rv;
1027 :
1028 216 : app_wrk = app_worker_alloc (app);
1029 216 : wrk_map = app_worker_map_alloc (app);
1030 216 : wrk_map->wrk_index = app_wrk->wrk_index;
1031 216 : app_wrk->wrk_map_index = app_worker_map_index (app, wrk_map);
1032 :
1033 : /*
1034 : * Setup first segment manager
1035 : */
1036 216 : sm = segment_manager_alloc ();
1037 216 : sm->app_wrk_index = app_wrk->wrk_index;
1038 :
1039 216 : if ((rv = segment_manager_init_first (sm)))
1040 : {
1041 0 : app_worker_free (app_wrk);
1042 0 : return rv;
1043 : }
1044 216 : sm->first_is_protected = 1;
1045 :
1046 : /*
1047 : * Setup app worker
1048 : */
1049 216 : app_wrk->connects_seg_manager = segment_manager_index (sm);
1050 216 : app_wrk->listeners_table = hash_create (0, sizeof (u64));
1051 216 : app_wrk->event_queue = segment_manager_event_queue (sm);
1052 216 : app_wrk->app_is_builtin = application_is_builtin (app);
1053 :
1054 216 : *wrk = app_wrk;
1055 :
1056 216 : return 0;
1057 : }
1058 :
1059 : session_error_t
1060 43 : vnet_app_worker_add_del (vnet_app_worker_add_del_args_t *a)
1061 : {
1062 : fifo_segment_t *fs;
1063 : app_worker_map_t *wrk_map;
1064 : app_worker_t *app_wrk;
1065 : segment_manager_t *sm;
1066 : application_t *app;
1067 : int rv;
1068 :
1069 43 : app = application_get (a->app_index);
1070 43 : if (!app)
1071 0 : return SESSION_E_INVALID;
1072 :
1073 43 : if (a->is_add)
1074 : {
1075 0 : if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
1076 0 : return rv;
1077 :
1078 : /* Map worker api index to the app */
1079 0 : app_wrk->api_client_index = a->api_client_index;
1080 0 : application_api_table_add (app->app_index, a->api_client_index);
1081 :
1082 0 : sm = segment_manager_get (app_wrk->connects_seg_manager);
1083 0 : fs = segment_manager_get_segment_w_lock (sm, 0);
1084 0 : a->segment = &fs->ssvm;
1085 0 : a->segment_handle = segment_manager_segment_handle (sm, fs);
1086 0 : segment_manager_segment_reader_unlock (sm);
1087 0 : a->evt_q = app_wrk->event_queue;
1088 0 : a->wrk_map_index = app_wrk->wrk_map_index;
1089 : }
1090 : else
1091 : {
1092 43 : wrk_map = app_worker_map_get (app, a->wrk_map_index);
1093 43 : if (!wrk_map)
1094 0 : return SESSION_E_INVALID;
1095 :
1096 43 : app_wrk = app_worker_get (wrk_map->wrk_index);
1097 43 : if (!app_wrk)
1098 0 : return SESSION_E_INVALID;
1099 :
1100 43 : application_api_table_del (app_wrk->api_client_index);
1101 43 : if (appns_sapi_enabled ())
1102 14 : sapi_socket_close_w_handle (app_wrk->api_client_index);
1103 43 : app_worker_free (app_wrk);
1104 43 : app_worker_map_free (app, wrk_map);
1105 43 : if (application_n_workers (app) == 0)
1106 43 : application_free (app);
1107 : }
1108 43 : return 0;
1109 : }
1110 :
1111 : static session_error_t
1112 203 : app_validate_namespace (u8 *namespace_id, u64 secret, u32 *app_ns_index)
1113 : {
1114 : app_namespace_t *app_ns;
1115 203 : if (vec_len (namespace_id) == 0)
1116 : {
1117 : /* Use default namespace */
1118 149 : *app_ns_index = 0;
1119 149 : return 0;
1120 : }
1121 :
1122 54 : *app_ns_index = app_namespace_index_from_id (namespace_id);
1123 54 : if (*app_ns_index == APP_NAMESPACE_INVALID_INDEX)
1124 0 : return SESSION_E_INVALID_NS;
1125 54 : app_ns = app_namespace_get (*app_ns_index);
1126 54 : if (!app_ns)
1127 0 : return SESSION_E_INVALID_NS;
1128 54 : if (app_ns->ns_secret != secret)
1129 1 : return SESSION_E_WRONG_NS_SECRET;
1130 53 : return 0;
1131 : }
1132 :
1133 : static u8 *
1134 43 : app_name_from_api_index (u32 api_client_index)
1135 : {
1136 : vl_api_registration_t *regp;
1137 43 : regp = vl_api_client_index_to_registration (api_client_index);
1138 43 : if (regp)
1139 43 : return format (0, "%s", regp->name);
1140 :
1141 0 : clib_warning ("api client index %u does not have an api registration!",
1142 : api_client_index);
1143 0 : return format (0, "unknown");
1144 : }
1145 :
1146 : /**
1147 : * Attach application to vpp
1148 : *
1149 : * Allocates a vpp app, i.e., a structure that keeps back pointers
1150 : * to external app and a segment manager for shared memory fifo based
1151 : * communication with the external app.
1152 : */
1153 : session_error_t
1154 217 : vnet_application_attach (vnet_app_attach_args_t *a)
1155 : {
1156 : fifo_segment_t *fs;
1157 217 : application_t *app = 0;
1158 : app_worker_t *app_wrk;
1159 : segment_manager_t *sm;
1160 217 : u32 app_ns_index = 0;
1161 217 : u8 *app_name = 0;
1162 : u64 secret;
1163 : session_error_t rv;
1164 :
1165 217 : if (a->api_client_index != APP_INVALID_INDEX)
1166 57 : app = application_lookup (a->api_client_index);
1167 160 : else if (a->name)
1168 160 : app = application_lookup_name (a->name);
1169 : else
1170 0 : return SESSION_E_INVALID;
1171 :
1172 217 : if (app)
1173 0 : return SESSION_E_APP_ATTACHED;
1174 :
1175 : /* Socket api sets the name and validates namespace prior to attach */
1176 217 : if (!a->use_sock_api)
1177 : {
1178 203 : if (a->api_client_index != APP_INVALID_INDEX)
1179 : {
1180 43 : app_name = app_name_from_api_index (a->api_client_index);
1181 43 : a->name = app_name;
1182 : }
1183 :
1184 203 : secret = a->options[APP_OPTIONS_NAMESPACE_SECRET];
1185 203 : if ((rv = app_validate_namespace (a->namespace_id, secret,
1186 : &app_ns_index)))
1187 1 : return rv;
1188 202 : a->options[APP_OPTIONS_NAMESPACE] = app_ns_index;
1189 : }
1190 :
1191 216 : if ((rv = application_alloc_and_init ((app_init_args_t *) a)))
1192 0 : return rv;
1193 :
1194 216 : app = application_get (a->app_index);
1195 216 : if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
1196 0 : return rv;
1197 :
1198 216 : a->app_evt_q = app_wrk->event_queue;
1199 216 : app_wrk->api_client_index = a->api_client_index;
1200 216 : sm = segment_manager_get (app_wrk->connects_seg_manager);
1201 216 : fs = segment_manager_get_segment_w_lock (sm, 0);
1202 :
1203 216 : if (application_is_proxy (app))
1204 : {
1205 1 : application_setup_proxy (app);
1206 : /* The segment manager pool is reallocated because a new listener
1207 : * is added. Re-grab segment manager to avoid dangling reference */
1208 1 : sm = segment_manager_get (app_wrk->connects_seg_manager);
1209 : }
1210 :
1211 216 : ASSERT (vec_len (fs->ssvm.name) <= 128);
1212 216 : a->segment = &fs->ssvm;
1213 216 : a->segment_handle = segment_manager_segment_handle (sm, fs);
1214 :
1215 216 : segment_manager_segment_reader_unlock (sm);
1216 :
1217 216 : if (!application_is_builtin (app) && application_use_private_rx_mqs ())
1218 4 : rv = app_rx_mqs_alloc (app);
1219 :
1220 216 : vec_free (app_name);
1221 216 : return rv;
1222 : }
1223 :
1224 : /**
1225 : * Detach application from vpp
1226 : */
1227 : session_error_t
1228 66 : vnet_application_detach (vnet_app_detach_args_t *a)
1229 : {
1230 : application_t *app;
1231 :
1232 66 : app = application_get_if_valid (a->app_index);
1233 66 : if (!app)
1234 : {
1235 0 : clib_warning ("app not attached");
1236 0 : return SESSION_E_NOAPP;
1237 : }
1238 :
1239 66 : app_interface_check_thread_and_barrier (vnet_application_detach, a);
1240 66 : application_detach_process (app, a->api_client_index);
1241 66 : return 0;
1242 : }
1243 :
1244 : static u8
1245 73 : session_endpoint_in_ns (session_endpoint_cfg_t *sep)
1246 : {
1247 : u8 is_lep;
1248 :
1249 73 : if (sep->flags & SESSION_ENDPT_CFG_F_PROXY_LISTEN)
1250 0 : return 1;
1251 :
1252 73 : is_lep = session_endpoint_is_local ((session_endpoint_t *) sep);
1253 73 : if (!is_lep && sep->sw_if_index != ENDPOINT_INVALID_INDEX
1254 13 : && !ip_interface_has_address (sep->sw_if_index, &sep->ip, sep->is_ip4))
1255 : {
1256 0 : clib_warning ("sw_if_index %u not configured with ip %U",
1257 : sep->sw_if_index, format_ip46_address, &sep->ip,
1258 : sep->is_ip4);
1259 0 : return 0;
1260 : }
1261 :
1262 73 : return (is_lep || ip_is_local (sep->fib_index, &sep->ip, sep->is_ip4));
1263 : }
1264 :
1265 : static void
1266 286 : session_endpoint_update_for_app (session_endpoint_cfg_t * sep,
1267 : application_t * app, u8 is_connect)
1268 : {
1269 : app_namespace_t *app_ns;
1270 : u32 ns_index, fib_index;
1271 :
1272 286 : ns_index = app->ns_index;
1273 :
1274 : /* App is a transport proto, so fetch the calling app's ns */
1275 286 : if (app->flags & APP_OPTIONS_FLAGS_IS_TRANSPORT_APP)
1276 32 : ns_index = sep->ns_index;
1277 :
1278 286 : app_ns = app_namespace_get (ns_index);
1279 286 : if (!app_ns)
1280 0 : return;
1281 :
1282 : /* Ask transport and network to bind to/connect using local interface
1283 : * that "supports" app's namespace. This will fix our local connection
1284 : * endpoint.
1285 : */
1286 :
1287 : /* If in default namespace and user requested a fib index use it */
1288 286 : if (ns_index == 0 && sep->fib_index != ENDPOINT_INVALID_INDEX)
1289 34 : fib_index = sep->fib_index;
1290 : else
1291 252 : fib_index = sep->is_ip4 ? app_ns->ip4_fib_index : app_ns->ip6_fib_index;
1292 286 : sep->peer.fib_index = fib_index;
1293 286 : sep->fib_index = fib_index;
1294 :
1295 286 : if (!is_connect)
1296 : {
1297 73 : sep->sw_if_index = app_ns->sw_if_index;
1298 : }
1299 : else
1300 : {
1301 213 : if (app_ns->sw_if_index != APP_NAMESPACE_INVALID_INDEX
1302 195 : && sep->peer.sw_if_index != ENDPOINT_INVALID_INDEX
1303 129 : && sep->peer.sw_if_index != app_ns->sw_if_index)
1304 0 : clib_warning ("Local sw_if_index different from app ns sw_if_index");
1305 :
1306 213 : sep->peer.sw_if_index = app_ns->sw_if_index;
1307 : }
1308 : }
1309 :
1310 : session_error_t
1311 73 : vnet_listen (vnet_listen_args_t *a)
1312 : {
1313 : app_listener_t *app_listener;
1314 : app_worker_t *app_wrk;
1315 : application_t *app;
1316 : int rv;
1317 :
1318 73 : ASSERT (vlib_thread_is_main_w_barrier ());
1319 :
1320 73 : app = application_get_if_valid (a->app_index);
1321 73 : if (!app)
1322 0 : return SESSION_E_NOAPP;
1323 :
1324 73 : app_wrk = application_get_worker (app, a->wrk_map_index);
1325 73 : if (!app_wrk)
1326 0 : return SESSION_E_INVALID_APPWRK;
1327 :
1328 73 : a->sep_ext.app_wrk_index = app_wrk->wrk_index;
1329 :
1330 73 : session_endpoint_update_for_app (&a->sep_ext, app, 0 /* is_connect */ );
1331 73 : if (!session_endpoint_in_ns (&a->sep_ext))
1332 0 : return SESSION_E_INVALID_NS;
1333 :
1334 : /*
1335 : * Check if we already have an app listener
1336 : */
1337 73 : app_listener = app_listener_lookup (app, &a->sep_ext);
1338 73 : if (app_listener)
1339 : {
1340 2 : if (app_listener->app_index != app->app_index)
1341 0 : return SESSION_E_ALREADY_LISTENING;
1342 2 : if ((rv = app_worker_start_listen (app_wrk, app_listener)))
1343 2 : return rv;
1344 0 : a->handle = app_listener_handle (app_listener);
1345 0 : return 0;
1346 : }
1347 :
1348 : /*
1349 : * Create new app listener
1350 : */
1351 71 : if ((rv = app_listener_alloc_and_init (app, &a->sep_ext, &app_listener)))
1352 0 : return rv;
1353 :
1354 71 : if ((rv = app_worker_start_listen (app_wrk, app_listener)))
1355 : {
1356 0 : app_listener_cleanup (app_listener);
1357 0 : return rv;
1358 : }
1359 :
1360 71 : a->handle = app_listener_handle (app_listener);
1361 71 : return 0;
1362 : }
1363 :
1364 : session_error_t
1365 214 : vnet_connect (vnet_connect_args_t *a)
1366 : {
1367 : app_worker_t *client_wrk;
1368 : application_t *client;
1369 :
1370 214 : ASSERT (session_vlib_thread_is_cl_thread ());
1371 :
1372 214 : if (session_endpoint_is_zero (&a->sep))
1373 1 : return SESSION_E_INVALID_RMT_IP;
1374 :
1375 213 : client = application_get (a->app_index);
1376 213 : session_endpoint_update_for_app (&a->sep_ext, client, 1 /* is_connect */ );
1377 213 : client_wrk = application_get_worker (client, a->wrk_map_index);
1378 :
1379 213 : a->sep_ext.opaque = a->api_context;
1380 :
1381 : /*
1382 : * First check the local scope for locally attached destinations.
1383 : * If we have local scope, we pass *all* connects through it since we may
1384 : * have special policy rules even for non-local destinations, think proxy.
1385 : */
1386 213 : if (application_has_local_scope (client))
1387 : {
1388 : session_error_t rv;
1389 :
1390 17 : a->sep_ext.original_tp = a->sep_ext.transport_proto;
1391 17 : a->sep_ext.transport_proto = TRANSPORT_PROTO_NONE;
1392 17 : rv = app_worker_connect_session (client_wrk, &a->sep_ext, &a->sh);
1393 17 : a->sep_ext.transport_proto = a->sep_ext.original_tp;
1394 17 : if (!rv || rv != SESSION_E_LOCAL_CONNECT)
1395 17 : return rv;
1396 : }
1397 : /*
1398 : * Not connecting to a local server, propagate to transport
1399 : */
1400 196 : return app_worker_connect_session (client_wrk, &a->sep_ext, &a->sh);
1401 : }
1402 :
1403 : session_error_t
1404 59 : vnet_unlisten (vnet_unlisten_args_t *a)
1405 : {
1406 : app_worker_t *app_wrk;
1407 : app_listener_t *al;
1408 : application_t *app;
1409 :
1410 59 : ASSERT (vlib_thread_is_main_w_barrier ());
1411 :
1412 59 : if (!(app = application_get_if_valid (a->app_index)))
1413 0 : return SESSION_E_NOAPP;
1414 :
1415 59 : if (!(al = app_listener_get_w_handle (a->handle)))
1416 2 : return SESSION_E_NOLISTEN;
1417 :
1418 57 : if (al->app_index != app->app_index)
1419 : {
1420 0 : clib_warning ("app doesn't own handle %llu!", a->handle);
1421 0 : return SESSION_E_OWNER;
1422 : }
1423 :
1424 57 : app_wrk = application_get_worker (app, a->wrk_map_index);
1425 57 : if (!app_wrk)
1426 : {
1427 0 : clib_warning ("no app %u worker %u", app->app_index, a->wrk_map_index);
1428 0 : return SESSION_E_INVALID_APPWRK;
1429 : }
1430 :
1431 57 : return app_worker_stop_listen (app_wrk, al);
1432 : }
1433 :
1434 : session_error_t
1435 0 : vnet_shutdown_session (vnet_shutdown_args_t *a)
1436 : {
1437 : app_worker_t *app_wrk;
1438 : session_t *s;
1439 :
1440 0 : s = session_get_from_handle_if_valid (a->handle);
1441 0 : if (!s)
1442 0 : return SESSION_E_NOSESSION;
1443 :
1444 0 : app_wrk = app_worker_get (s->app_wrk_index);
1445 0 : if (app_wrk->app_index != a->app_index)
1446 0 : return SESSION_E_OWNER;
1447 :
1448 : /* We're peeking into another's thread pool. Make sure */
1449 0 : ASSERT (s->session_index == session_index_from_handle (a->handle));
1450 :
1451 0 : session_half_close (s);
1452 0 : return 0;
1453 : }
1454 :
1455 : session_error_t
1456 372 : vnet_disconnect_session (vnet_disconnect_args_t *a)
1457 : {
1458 : app_worker_t *app_wrk;
1459 : session_t *s;
1460 :
1461 372 : s = session_get_from_handle_if_valid (a->handle);
1462 372 : if (!s)
1463 0 : return SESSION_E_NOSESSION;
1464 :
1465 372 : app_wrk = app_worker_get (s->app_wrk_index);
1466 372 : if (app_wrk->app_index != a->app_index)
1467 0 : return SESSION_E_OWNER;
1468 :
1469 : /* We're peeking into another's thread pool. Make sure */
1470 372 : ASSERT (s->session_index == session_index_from_handle (a->handle));
1471 :
1472 372 : session_close (s);
1473 372 : return 0;
1474 : }
1475 :
1476 : int
1477 0 : application_change_listener_owner (session_t * s, app_worker_t * app_wrk)
1478 : {
1479 0 : app_worker_t *old_wrk = app_worker_get (s->app_wrk_index);
1480 : app_listener_t *app_listener;
1481 : application_t *app;
1482 : int rv;
1483 :
1484 0 : if (!old_wrk)
1485 0 : return SESSION_E_INVALID_APPWRK;
1486 :
1487 0 : hash_unset (old_wrk->listeners_table, listen_session_get_handle (s));
1488 0 : if (session_transport_service_type (s) == TRANSPORT_SERVICE_CL
1489 0 : && s->rx_fifo)
1490 0 : segment_manager_dealloc_fifos (s->rx_fifo, s->tx_fifo);
1491 :
1492 0 : app = application_get (old_wrk->app_index);
1493 0 : if (!app)
1494 0 : return SESSION_E_NOAPP;
1495 :
1496 0 : app_listener = app_listener_get (app, s->al_index);
1497 :
1498 : /* Only remove from lb for now */
1499 0 : app_listener->workers = clib_bitmap_set (app_listener->workers,
1500 0 : old_wrk->wrk_map_index, 0);
1501 :
1502 0 : if ((rv = app_worker_start_listen (app_wrk, app_listener)))
1503 0 : return rv;
1504 :
1505 0 : s->app_wrk_index = app_wrk->wrk_index;
1506 :
1507 0 : return 0;
1508 : }
1509 :
1510 : int
1511 565 : application_is_proxy (application_t * app)
1512 : {
1513 565 : return (app->flags & APP_OPTIONS_FLAGS_IS_PROXY);
1514 : }
1515 :
1516 : int
1517 735 : application_is_builtin (application_t * app)
1518 : {
1519 735 : return (app->flags & APP_OPTIONS_FLAGS_IS_BUILTIN);
1520 : }
1521 :
1522 : int
1523 225 : application_is_builtin_proxy (application_t * app)
1524 : {
1525 225 : return (application_is_proxy (app) && application_is_builtin (app));
1526 : }
1527 :
1528 : u8
1529 556 : application_has_local_scope (application_t * app)
1530 : {
1531 556 : return app->flags & APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1532 : }
1533 :
1534 : u8
1535 295 : application_has_global_scope (application_t * app)
1536 : {
1537 295 : return app->flags & APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1538 : }
1539 :
1540 : int
1541 47 : application_original_dst_is_enabled (application_t *app)
1542 : {
1543 47 : return app->flags & APP_OPTIONS_FLAGS_GET_ORIGINAL_DST;
1544 : }
1545 :
1546 : static clib_error_t *
1547 4 : application_start_stop_proxy_fib_proto (application_t * app, u8 fib_proto,
1548 : u8 transport_proto, u8 is_start)
1549 : {
1550 4 : app_namespace_t *app_ns = app_namespace_get (app->ns_index);
1551 4 : u8 is_ip4 = (fib_proto == FIB_PROTOCOL_IP4);
1552 4 : session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
1553 : transport_connection_t *tc;
1554 : app_worker_t *app_wrk;
1555 : app_listener_t *al;
1556 : session_t *s;
1557 : u32 flags;
1558 :
1559 : /* TODO decide if we want proxy to be enabled for all workers */
1560 4 : app_wrk = application_get_default_worker (app);
1561 4 : if (is_start)
1562 : {
1563 2 : s = app_worker_first_listener (app_wrk, fib_proto, transport_proto);
1564 2 : if (!s)
1565 : {
1566 2 : sep.is_ip4 = is_ip4;
1567 2 : sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1568 2 : sep.sw_if_index = app_ns->sw_if_index;
1569 2 : sep.transport_proto = transport_proto;
1570 2 : sep.app_wrk_index = app_wrk->wrk_index; /* only default */
1571 :
1572 : /* force global scope listener */
1573 2 : flags = app->flags;
1574 2 : app->flags &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1575 2 : app_listener_alloc_and_init (app, &sep, &al);
1576 2 : app->flags = flags;
1577 :
1578 2 : app_worker_start_listen (app_wrk, al);
1579 2 : s = listen_session_get (al->session_index);
1580 2 : s->flags |= SESSION_F_PROXY;
1581 : }
1582 : }
1583 : else
1584 : {
1585 2 : s = app_worker_proxy_listener (app_wrk, fib_proto, transport_proto);
1586 2 : ASSERT (s);
1587 : }
1588 :
1589 4 : tc = listen_session_get_transport (s);
1590 :
1591 4 : if (!ip_is_zero (&tc->lcl_ip, 1))
1592 : {
1593 : u32 sti;
1594 2 : sep.is_ip4 = is_ip4;
1595 2 : sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1596 2 : sep.transport_proto = transport_proto;
1597 2 : sep.port = 0;
1598 2 : sti = session_lookup_get_index_for_fib (fib_proto, sep.fib_index);
1599 2 : if (is_start)
1600 1 : session_lookup_add_session_endpoint (sti,
1601 : (session_endpoint_t *) & sep,
1602 1 : s->session_index);
1603 : else
1604 1 : session_lookup_del_session_endpoint (sti,
1605 : (session_endpoint_t *) & sep);
1606 : }
1607 :
1608 4 : return 0;
1609 : }
1610 :
1611 : static void
1612 2 : application_start_stop_proxy_local_scope (application_t * app,
1613 : u8 transport_proto, u8 is_start)
1614 : {
1615 2 : session_endpoint_t sep = SESSION_ENDPOINT_NULL;
1616 : app_namespace_t *app_ns;
1617 2 : app_ns = app_namespace_get (app->ns_index);
1618 2 : sep.is_ip4 = 1;
1619 2 : sep.transport_proto = transport_proto;
1620 2 : sep.port = 0;
1621 :
1622 2 : if (is_start)
1623 : {
1624 1 : session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
1625 1 : app->app_index);
1626 1 : sep.is_ip4 = 0;
1627 1 : session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
1628 1 : app->app_index);
1629 : }
1630 : else
1631 : {
1632 1 : session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1633 1 : sep.is_ip4 = 0;
1634 1 : session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1635 : }
1636 2 : }
1637 :
1638 : void
1639 2 : application_start_stop_proxy (application_t * app,
1640 : transport_proto_t transport_proto, u8 is_start)
1641 : {
1642 2 : if (application_has_local_scope (app))
1643 2 : application_start_stop_proxy_local_scope (app, transport_proto, is_start);
1644 :
1645 2 : if (application_has_global_scope (app))
1646 : {
1647 2 : application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP4,
1648 : transport_proto, is_start);
1649 2 : application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP6,
1650 : transport_proto, is_start);
1651 : }
1652 2 : }
1653 :
1654 : void
1655 1 : application_setup_proxy (application_t * app)
1656 : {
1657 1 : u16 transports = app->proxied_transports;
1658 : transport_proto_t tp;
1659 :
1660 1 : ASSERT (application_is_proxy (app));
1661 :
1662 9 : transport_proto_foreach (tp, transports)
1663 1 : application_start_stop_proxy (app, tp, 1);
1664 1 : }
1665 :
1666 : void
1667 1 : application_remove_proxy (application_t * app)
1668 : {
1669 1 : u16 transports = app->proxied_transports;
1670 : transport_proto_t tp;
1671 :
1672 1 : ASSERT (application_is_proxy (app));
1673 :
1674 9 : transport_proto_foreach (tp, transports)
1675 1 : application_start_stop_proxy (app, tp, 0);
1676 1 : }
1677 :
1678 : segment_manager_props_t *
1679 242 : application_segment_manager_properties (application_t * app)
1680 : {
1681 242 : return &app->sm_properties;
1682 : }
1683 :
1684 : segment_manager_props_t *
1685 1219 : application_get_segment_manager_properties (u32 app_index)
1686 : {
1687 1219 : application_t *app = application_get (app_index);
1688 1219 : return &app->sm_properties;
1689 : }
1690 :
1691 : static void
1692 15 : application_format_listeners (application_t * app, int verbose)
1693 : {
1694 15 : vlib_main_t *vm = vlib_get_main ();
1695 : app_worker_map_t *wrk_map;
1696 : app_worker_t *app_wrk;
1697 : u32 sm_index;
1698 : u64 handle;
1699 :
1700 15 : if (!app)
1701 : {
1702 5 : vlib_cli_output (vm, "%U", format_app_worker_listener, NULL /* header */,
1703 : 0, 0, verbose);
1704 5 : return;
1705 : }
1706 :
1707 : /* *INDENT-OFF* */
1708 20 : pool_foreach (wrk_map, app->worker_maps) {
1709 10 : app_wrk = app_worker_get (wrk_map->wrk_index);
1710 10 : if (hash_elts (app_wrk->listeners_table) == 0)
1711 10 : continue;
1712 10 : hash_foreach (handle, sm_index, app_wrk->listeners_table, ({
1713 : vlib_cli_output (vm, "%U", format_app_worker_listener, app_wrk,
1714 : handle, sm_index, verbose);
1715 : }));
1716 : }
1717 : /* *INDENT-ON* */
1718 : }
1719 :
1720 : static void
1721 0 : application_format_connects (application_t * app, int verbose)
1722 : {
1723 : app_worker_map_t *wrk_map;
1724 : app_worker_t *app_wrk;
1725 :
1726 0 : if (!app)
1727 : {
1728 0 : app_worker_format_connects (0, verbose);
1729 0 : return;
1730 : }
1731 :
1732 : /* *INDENT-OFF* */
1733 0 : pool_foreach (wrk_map, app->worker_maps) {
1734 0 : app_wrk = app_worker_get (wrk_map->wrk_index);
1735 0 : app_worker_format_connects (app_wrk, verbose);
1736 : }
1737 : /* *INDENT-ON* */
1738 : }
1739 :
1740 : u8 *
1741 0 : format_cert_key_pair (u8 * s, va_list * args)
1742 : {
1743 0 : app_cert_key_pair_t *ckpair = va_arg (*args, app_cert_key_pair_t *);
1744 0 : int key_len = 0, cert_len = 0;
1745 0 : cert_len = vec_len (ckpair->cert);
1746 0 : key_len = vec_len (ckpair->key);
1747 0 : if (ckpair->cert_key_index == 0)
1748 0 : s = format (s, "DEFAULT (cert:%d, key:%d)", cert_len, key_len);
1749 : else
1750 0 : s = format (s, "%d (cert:%d, key:%d)", ckpair->cert_key_index,
1751 : cert_len, key_len);
1752 0 : return s;
1753 : }
1754 :
1755 : u8 *
1756 0 : format_crypto_engine (u8 * s, va_list * args)
1757 : {
1758 0 : u32 engine = va_arg (*args, u32);
1759 0 : switch (engine)
1760 : {
1761 0 : case CRYPTO_ENGINE_NONE:
1762 0 : return format (s, "none");
1763 0 : case CRYPTO_ENGINE_MBEDTLS:
1764 0 : return format (s, "mbedtls");
1765 0 : case CRYPTO_ENGINE_OPENSSL:
1766 0 : return format (s, "openssl");
1767 0 : case CRYPTO_ENGINE_PICOTLS:
1768 0 : return format (s, "picotls");
1769 0 : case CRYPTO_ENGINE_VPP:
1770 0 : return format (s, "vpp");
1771 0 : default:
1772 0 : return format (s, "unknown engine");
1773 : }
1774 : return s;
1775 : }
1776 :
1777 : uword
1778 0 : unformat_crypto_engine (unformat_input_t * input, va_list * args)
1779 : {
1780 0 : u8 *a = va_arg (*args, u8 *);
1781 0 : if (unformat (input, "mbedtls"))
1782 0 : *a = CRYPTO_ENGINE_MBEDTLS;
1783 0 : else if (unformat (input, "openssl"))
1784 0 : *a = CRYPTO_ENGINE_OPENSSL;
1785 0 : else if (unformat (input, "picotls"))
1786 0 : *a = CRYPTO_ENGINE_PICOTLS;
1787 0 : else if (unformat (input, "vpp"))
1788 0 : *a = CRYPTO_ENGINE_VPP;
1789 : else
1790 0 : return 0;
1791 0 : return 1;
1792 : }
1793 :
1794 : u8 *
1795 0 : format_crypto_context (u8 * s, va_list * args)
1796 : {
1797 0 : crypto_context_t *crctx = va_arg (*args, crypto_context_t *);
1798 0 : s = format (s, "[0x%x][sub%d,ckpair%x]", crctx->ctx_index,
1799 : crctx->n_subscribers, crctx->ckpair_index);
1800 0 : s = format (s, "[%U]", format_crypto_engine, crctx->crypto_engine);
1801 0 : return s;
1802 : }
1803 :
1804 : u8 *
1805 0 : format_application (u8 * s, va_list * args)
1806 : {
1807 0 : application_t *app = va_arg (*args, application_t *);
1808 0 : CLIB_UNUSED (int verbose) = va_arg (*args, int);
1809 : segment_manager_props_t *props;
1810 : const u8 *app_ns_name, *app_name;
1811 : app_worker_map_t *wrk_map;
1812 : app_worker_t *app_wrk;
1813 :
1814 0 : if (app == 0)
1815 : {
1816 0 : if (!verbose)
1817 0 : s = format (s, "%-10s%-20s%-40s", "Index", "Name", "Namespace");
1818 0 : return s;
1819 : }
1820 :
1821 0 : app_name = app_get_name (app);
1822 0 : app_ns_name = app_namespace_id_from_index (app->ns_index);
1823 0 : props = application_segment_manager_properties (app);
1824 0 : if (!verbose)
1825 : {
1826 0 : s = format (s, "%-10u%-20v%-40v", app->app_index, app_name,
1827 : app_ns_name);
1828 0 : return s;
1829 : }
1830 :
1831 0 : s = format (s, "app-name %v app-index %u ns-index %u seg-size %U\n",
1832 : app_name, app->app_index, app->ns_index,
1833 : format_memory_size, props->add_segment_size);
1834 0 : s = format (s, "rx-fifo-size %U tx-fifo-size %U workers:\n",
1835 : format_memory_size, props->rx_fifo_size,
1836 : format_memory_size, props->tx_fifo_size);
1837 :
1838 : /* *INDENT-OFF* */
1839 0 : pool_foreach (wrk_map, app->worker_maps) {
1840 0 : app_wrk = app_worker_get (wrk_map->wrk_index);
1841 0 : s = format (s, "%U", format_app_worker, app_wrk);
1842 : }
1843 : /* *INDENT-ON* */
1844 :
1845 0 : return s;
1846 : }
1847 :
1848 : void
1849 5 : application_format_all_listeners (vlib_main_t * vm, int verbose)
1850 : {
1851 : application_t *app;
1852 :
1853 5 : if (!pool_elts (app_main.app_pool))
1854 : {
1855 0 : vlib_cli_output (vm, "No active server bindings");
1856 0 : return;
1857 : }
1858 :
1859 5 : application_format_listeners (0, verbose);
1860 :
1861 : /* *INDENT-OFF* */
1862 15 : pool_foreach (app, app_main.app_pool) {
1863 10 : application_format_listeners (app, verbose);
1864 : }
1865 : /* *INDENT-ON* */
1866 : }
1867 :
1868 : void
1869 0 : application_format_all_clients (vlib_main_t * vm, int verbose)
1870 : {
1871 : application_t *app;
1872 :
1873 0 : if (!pool_elts (app_main.app_pool))
1874 : {
1875 0 : vlib_cli_output (vm, "No active apps");
1876 0 : return;
1877 : }
1878 :
1879 0 : application_format_connects (0, verbose);
1880 :
1881 : /* *INDENT-OFF* */
1882 0 : pool_foreach (app, app_main.app_pool) {
1883 0 : application_format_connects (app, verbose);
1884 : }
1885 : /* *INDENT-ON* */
1886 : }
1887 :
1888 : static clib_error_t *
1889 0 : show_certificate_command_fn (vlib_main_t * vm, unformat_input_t * input,
1890 : vlib_cli_command_t * cmd)
1891 : {
1892 : app_cert_key_pair_t *ckpair;
1893 0 : session_cli_return_if_not_enabled ();
1894 :
1895 : /* *INDENT-OFF* */
1896 0 : pool_foreach (ckpair, app_main.cert_key_pair_store) {
1897 0 : vlib_cli_output (vm, "%U", format_cert_key_pair, ckpair);
1898 : }
1899 : /* *INDENT-ON* */
1900 0 : return 0;
1901 : }
1902 :
1903 : static inline void
1904 44 : appliction_format_app_mq (vlib_main_t * vm, application_t * app)
1905 : {
1906 : app_worker_map_t *map;
1907 : app_worker_t *wrk;
1908 : int i;
1909 :
1910 : /* *INDENT-OFF* */
1911 88 : pool_foreach (map, app->worker_maps) {
1912 44 : wrk = app_worker_get (map->wrk_index);
1913 44 : vlib_cli_output (vm, "[A%d][%d]%U", app->app_index,
1914 : map->wrk_index, format_svm_msg_q,
1915 : wrk->event_queue);
1916 : }
1917 : /* *INDENT-ON* */
1918 :
1919 44 : for (i = 0; i < vec_len (app->rx_mqs); i++)
1920 0 : vlib_cli_output (vm, "[A%d][R%d]%U", app->app_index, i, format_svm_msg_q,
1921 0 : app->rx_mqs[i].mq);
1922 44 : }
1923 :
1924 : static clib_error_t *
1925 16 : appliction_format_all_app_mq (vlib_main_t * vm)
1926 : {
1927 : application_t *app;
1928 : int i, n_threads;
1929 :
1930 16 : n_threads = vlib_get_n_threads ();
1931 :
1932 32 : for (i = 0; i < n_threads; i++)
1933 : {
1934 16 : vlib_cli_output (vm, "[Ctrl%d]%U", i, format_svm_msg_q,
1935 : session_main_get_vpp_event_queue (i));
1936 : }
1937 :
1938 : /* *INDENT-OFF* */
1939 60 : pool_foreach (app, app_main.app_pool) {
1940 44 : appliction_format_app_mq (vm, app);
1941 : }
1942 : /* *INDENT-ON* */
1943 16 : return 0;
1944 : }
1945 :
1946 : static clib_error_t *
1947 21 : show_app_command_fn (vlib_main_t * vm, unformat_input_t * input,
1948 : vlib_cli_command_t * cmd)
1949 : {
1950 21 : int do_server = 0, do_client = 0, do_mq = 0, do_transports = 0;
1951 : application_t *app;
1952 21 : u32 app_index = ~0;
1953 21 : int verbose = 0;
1954 : u8 is_ta;
1955 :
1956 21 : session_cli_return_if_not_enabled ();
1957 :
1958 42 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1959 : {
1960 21 : if (unformat (input, "server"))
1961 5 : do_server = 1;
1962 16 : else if (unformat (input, "client"))
1963 0 : do_client = 1;
1964 16 : else if (unformat (input, "transports"))
1965 0 : do_transports = 1;
1966 16 : else if (unformat (input, "mq"))
1967 16 : do_mq = 1;
1968 0 : else if (unformat (input, "%u", &app_index))
1969 : ;
1970 0 : else if (unformat (input, "verbose"))
1971 0 : verbose = 1;
1972 : else
1973 0 : return clib_error_return (0, "unknown input `%U'",
1974 : format_unformat_error, input);
1975 : }
1976 :
1977 21 : if (do_mq && app_index != ~0)
1978 : {
1979 0 : app = application_get_if_valid (app_index);
1980 0 : if (!app)
1981 0 : return clib_error_return (0, "No app with index %u", app_index);
1982 :
1983 0 : appliction_format_app_mq (vm, app);
1984 0 : return 0;
1985 : }
1986 :
1987 21 : if (do_mq)
1988 : {
1989 16 : appliction_format_all_app_mq (vm);
1990 16 : return 0;
1991 : }
1992 :
1993 5 : if (do_server)
1994 : {
1995 5 : application_format_all_listeners (vm, verbose);
1996 5 : return 0;
1997 : }
1998 :
1999 0 : if (do_client)
2000 : {
2001 0 : application_format_all_clients (vm, verbose);
2002 0 : return 0;
2003 : }
2004 :
2005 0 : if (app_index != ~0)
2006 : {
2007 0 : app = application_get_if_valid (app_index);
2008 0 : if (!app)
2009 0 : return clib_error_return (0, "No app with index %u", app_index);
2010 :
2011 0 : vlib_cli_output (vm, "%U", format_application, app, /* verbose */ 1);
2012 0 : return 0;
2013 : }
2014 :
2015 : /* Print app related info */
2016 0 : if (!do_server && !do_client)
2017 : {
2018 0 : vlib_cli_output (vm, "%U", format_application, 0, 0);
2019 0 : pool_foreach (app, app_main.app_pool) {
2020 0 : is_ta = app->flags & APP_OPTIONS_FLAGS_IS_TRANSPORT_APP;
2021 0 : if ((!do_transports && !is_ta) || (do_transports && is_ta))
2022 0 : vlib_cli_output (vm, "%U", format_application, app, 0);
2023 : }
2024 : }
2025 :
2026 0 : return 0;
2027 : }
2028 :
2029 : /* Certificate store */
2030 :
2031 : static app_cert_key_pair_t *
2032 604 : app_cert_key_pair_alloc ()
2033 : {
2034 : app_cert_key_pair_t *ckpair;
2035 604 : pool_get (app_main.cert_key_pair_store, ckpair);
2036 604 : clib_memset (ckpair, 0, sizeof (*ckpair));
2037 604 : ckpair->cert_key_index = ckpair - app_main.cert_key_pair_store;
2038 604 : return ckpair;
2039 : }
2040 :
2041 : app_cert_key_pair_t *
2042 44 : app_cert_key_pair_get_if_valid (u32 index)
2043 : {
2044 44 : if (pool_is_free_index (app_main.cert_key_pair_store, index))
2045 0 : return 0;
2046 44 : return app_cert_key_pair_get (index);
2047 : }
2048 :
2049 : app_cert_key_pair_t *
2050 44 : app_cert_key_pair_get (u32 index)
2051 : {
2052 44 : return pool_elt_at_index (app_main.cert_key_pair_store, index);
2053 : }
2054 :
2055 : app_cert_key_pair_t *
2056 0 : app_cert_key_pair_get_default ()
2057 : {
2058 : /* To maintain legacy bapi */
2059 0 : return app_cert_key_pair_get (0);
2060 : }
2061 :
2062 : int
2063 29 : vnet_app_add_cert_key_pair (vnet_app_add_cert_key_pair_args_t * a)
2064 : {
2065 29 : app_cert_key_pair_t *ckpair = app_cert_key_pair_alloc ();
2066 29 : vec_validate (ckpair->cert, a->cert_len - 1);
2067 29 : clib_memcpy_fast (ckpair->cert, a->cert, a->cert_len);
2068 29 : vec_validate (ckpair->key, a->key_len - 1);
2069 29 : clib_memcpy_fast (ckpair->key, a->key, a->key_len);
2070 29 : a->index = ckpair->cert_key_index;
2071 29 : return 0;
2072 : }
2073 :
2074 : int
2075 12 : vnet_app_add_cert_key_interest (u32 index, u32 app_index)
2076 : {
2077 : app_cert_key_pair_t *ckpair;
2078 12 : if (!(ckpair = app_cert_key_pair_get_if_valid (index)))
2079 0 : return -1;
2080 12 : if (vec_search (ckpair->app_interests, app_index) != ~0)
2081 0 : vec_add1 (ckpair->app_interests, app_index);
2082 12 : return 0;
2083 : }
2084 :
2085 : int
2086 14 : vnet_app_del_cert_key_pair (u32 index)
2087 : {
2088 : app_cert_key_pair_t *ckpair;
2089 : application_t *app;
2090 : u32 *app_index;
2091 :
2092 14 : if (!(ckpair = app_cert_key_pair_get_if_valid (index)))
2093 0 : return SESSION_E_INVALID;
2094 :
2095 14 : vec_foreach (app_index, ckpair->app_interests)
2096 : {
2097 0 : if ((app = application_get_if_valid (*app_index))
2098 0 : && app->cb_fns.app_cert_key_pair_delete_callback)
2099 0 : app->cb_fns.app_cert_key_pair_delete_callback (ckpair);
2100 : }
2101 :
2102 14 : vec_free (ckpair->cert);
2103 14 : vec_free (ckpair->key);
2104 14 : pool_put (app_main.cert_key_pair_store, ckpair);
2105 14 : return 0;
2106 : }
2107 :
2108 : clib_error_t *
2109 575 : application_init (vlib_main_t * vm)
2110 : {
2111 575 : app_main_t *am = &app_main;
2112 : u32 n_workers;
2113 :
2114 575 : n_workers = vlib_num_workers ();
2115 :
2116 : /* Index 0 was originally used by legacy apis, maintain as invalid */
2117 575 : (void) app_cert_key_pair_alloc ();
2118 575 : am->last_crypto_engine = CRYPTO_ENGINE_LAST;
2119 575 : am->app_by_name = hash_create_vec (0, sizeof (u8), sizeof (uword));
2120 :
2121 575 : vec_validate (am->wrk, n_workers);
2122 :
2123 575 : return 0;
2124 : }
2125 :
2126 78335 : VLIB_INIT_FUNCTION (application_init);
2127 :
2128 285289 : VLIB_CLI_COMMAND (show_app_command, static) = {
2129 : .path = "show app",
2130 : .short_help = "show app [index] [server|client] [mq] [verbose] "
2131 : "[transports]",
2132 : .function = show_app_command_fn,
2133 : };
2134 :
2135 285289 : VLIB_CLI_COMMAND (show_certificate_command, static) = {
2136 : .path = "show app certificate",
2137 : .short_help = "list app certs and keys present in store",
2138 : .function = show_certificate_command_fn,
2139 : };
2140 :
2141 : crypto_engine_type_t
2142 0 : app_crypto_engine_type_add (void)
2143 : {
2144 0 : return (++app_main.last_crypto_engine);
2145 : }
2146 :
2147 : u8
2148 25 : app_crypto_engine_n_types (void)
2149 : {
2150 25 : return (app_main.last_crypto_engine + 1);
2151 : }
2152 :
2153 : /*
2154 : * fd.io coding-style-patch-verification: ON
2155 : *
2156 : * Local Variables:
2157 : * eval: (c-set-style "gnu")
2158 : * End:
2159 : */
|