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 469 : app_listener_get (application_t * app, u32 app_listener_index)
47 : {
48 469 : 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 204 : app_listener_get_w_session (session_t * ls)
68 : {
69 : application_t *app;
70 :
71 204 : app = application_get_if_valid (ls->app_index);
72 204 : if (!app)
73 2 : return 0;
74 202 : return app_listener_get (app, ls->al_index);
75 : }
76 :
77 : session_handle_t
78 72 : app_listen_session_handle (session_t * ls)
79 : {
80 : app_listener_t *al;
81 72 : al = app_listener_get_w_session (ls);
82 72 : if (!al)
83 2 : return listen_session_get_handle (ls);
84 70 : 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 670 : app_worker_map_get (application_t * app, u32 map_index)
347 : {
348 670 : if (pool_is_free_index (app->worker_maps, map_index))
349 0 : return 0;
350 670 : 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 1490 : application_lookup (u32 api_client_index)
423 : {
424 : uword *p;
425 1490 : p = hash_get (app_main.app_by_api_client_index, api_client_index);
426 1490 : if (p)
427 223 : return application_get_if_valid (p[0]);
428 :
429 1267 : 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 24 : 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 24 : if (!aw->pending_rx_mqs)
449 : {
450 21 : elt->next = elt->prev = elt;
451 21 : aw->pending_rx_mqs = elt;
452 21 : 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 24 : appsl_pending_rx_mqs_del (appsl_wrk_t *aw, app_rx_mq_elt_t *elt)
468 : {
469 24 : if (elt->next == elt)
470 : {
471 21 : elt->next = elt->prev = 0;
472 21 : aw->pending_rx_mqs = 0;
473 21 : 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 583 : VLIB_NODE_FN (appsl_rx_mqs_input_node)
487 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
488 : {
489 24 : u32 thread_index = vm->thread_index, n_msgs = 0;
490 : app_rx_mq_elt_t *elt, *next;
491 24 : 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 24 : aw = &am->wrk[thread_index];
498 24 : elt = aw->pending_rx_mqs;
499 24 : if (!elt)
500 2 : return 0;
501 :
502 22 : wrk = session_main_get_worker (thread_index);
503 :
504 : do
505 : {
506 22 : if (!(elt->flags & APP_RX_MQ_F_POSTPONED))
507 22 : rv = read (svm_msg_q_get_eventfd (elt->mq), &buf, sizeof (buf));
508 22 : n_msgs += session_wrk_handle_mq (wrk, elt->mq);
509 :
510 22 : next = elt->next;
511 22 : appsl_pending_rx_mqs_del (aw, elt);
512 22 : if (!svm_msg_q_is_empty (elt->mq))
513 : {
514 1 : elt->flags |= APP_RX_MQ_F_POSTPONED;
515 1 : appsl_pending_rx_mqs_add_tail (aw, elt);
516 : }
517 : else
518 : {
519 21 : elt->flags = 0;
520 : }
521 22 : elt = next;
522 : }
523 22 : while (aw->pending_rx_mqs && elt != aw->pending_rx_mqs);
524 :
525 22 : if (aw->pending_rx_mqs)
526 4 : vlib_node_set_interrupt_pending (vm, appsl_rx_mqs_input_node.index);
527 :
528 22 : if (n_msgs && wrk->state == SESSION_WRK_INTERRUPT)
529 18 : vlib_node_set_interrupt_pending (vm, session_queue_node.index);
530 :
531 22 : return n_msgs;
532 : }
533 :
534 178120 : 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 27 : app_rx_mq_fd_read_ready (clib_file_t *cf)
542 : {
543 27 : app_rx_mq_handle_t *handle = (app_rx_mq_handle_t *) &cf->private_data;
544 27 : vlib_main_t *vm = vlib_get_main ();
545 27 : app_main_t *am = &app_main;
546 : app_rx_mq_elt_t *mqe;
547 : application_t *app;
548 : appsl_wrk_t *aw;
549 :
550 27 : ASSERT (vlib_get_thread_index () == handle->thread_index);
551 27 : app = application_get_if_valid (handle->app_index);
552 27 : if (!app)
553 0 : return 0;
554 :
555 27 : mqe = &app->rx_mqs[handle->thread_index];
556 27 : if ((mqe->flags & APP_RX_MQ_F_PENDING) || svm_msg_q_is_empty (mqe->mq))
557 4 : return 0;
558 :
559 23 : aw = &am->wrk[handle->thread_index];
560 23 : appsl_pending_rx_mqs_add_tail (aw, mqe);
561 23 : mqe->flags |= APP_RX_MQ_F_PENDING;
562 :
563 23 : vlib_node_set_interrupt_pending (vm, appsl_rx_mqs_input_node.index);
564 :
565 23 : 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 83840 : application_get (u32 app_index)
713 : {
714 83840 : if (app_index == APP_INVALID_INDEX)
715 0 : return 0;
716 83840 : return pool_elt_at_index (app_main.app_pool, app_index);
717 : }
718 :
719 : application_t *
720 671 : application_get_if_valid (u32 app_index)
721 : {
722 671 : if (pool_is_free_index (app_main.app_pool, app_index))
723 2 : return 0;
724 :
725 669 : return pool_elt_at_index (app_main.app_pool, app_index);
726 : }
727 :
728 : static void
729 216 : application_verify_cb_fns (session_cb_vft_t * cb_fns)
730 : {
731 216 : if (cb_fns->session_accept_callback == 0)
732 0 : clib_warning ("No accept callback function provided");
733 216 : if (cb_fns->session_connected_callback == 0)
734 0 : clib_warning ("No session connected callback function provided");
735 216 : if (cb_fns->session_disconnect_callback == 0)
736 0 : clib_warning ("No session disconnect callback function provided");
737 216 : if (cb_fns->session_reset_callback == 0)
738 0 : clib_warning ("No session reset callback function provided");
739 216 : }
740 :
741 : /**
742 : * Check app config for given segment type
743 : *
744 : * Returns 1 on success and 0 otherwise
745 : */
746 : static u8
747 216 : application_verify_cfg (ssvm_segment_type_t st)
748 : {
749 : u8 is_valid;
750 216 : if (st == SSVM_SEGMENT_MEMFD)
751 : {
752 57 : is_valid = (session_main_get_wrk_mqs_segment () != 0);
753 57 : if (!is_valid)
754 0 : clib_warning ("memfd seg: vpp's event qs IN binary api svm region");
755 57 : return is_valid;
756 : }
757 159 : else if (st == SSVM_SEGMENT_SHM)
758 : {
759 0 : is_valid = (session_main_get_wrk_mqs_segment () == 0);
760 0 : if (!is_valid)
761 0 : clib_warning ("shm seg: vpp's event qs NOT IN binary api svm region");
762 0 : return is_valid;
763 : }
764 : else
765 159 : return 1;
766 : }
767 :
768 : static int
769 216 : application_alloc_and_init (app_init_args_t * a)
770 : {
771 216 : ssvm_segment_type_t seg_type = SSVM_SEGMENT_MEMFD;
772 : segment_manager_props_t *props;
773 : application_t *app;
774 : u64 *opts;
775 :
776 216 : app = application_alloc ();
777 216 : opts = a->options;
778 : /*
779 : * Make sure we support the requested configuration
780 : */
781 216 : if ((opts[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_IS_BUILTIN) &&
782 159 : !(opts[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_MEMFD_FOR_BUILTIN))
783 159 : seg_type = SSVM_SEGMENT_PRIVATE;
784 :
785 216 : if ((opts[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD) &&
786 : seg_type != SSVM_SEGMENT_MEMFD)
787 : {
788 0 : clib_warning ("mq eventfds can only be used if socket transport is "
789 : "used for binary api");
790 0 : return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
791 : }
792 :
793 216 : if (!application_verify_cfg (seg_type))
794 0 : return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
795 :
796 216 : if (opts[APP_OPTIONS_PREALLOC_FIFO_PAIRS] &&
797 72 : opts[APP_OPTIONS_PREALLOC_FIFO_HDRS])
798 0 : return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
799 :
800 : /* Check that the obvious things are properly set up */
801 216 : application_verify_cb_fns (a->session_cb_vft);
802 :
803 216 : app->flags = opts[APP_OPTIONS_FLAGS];
804 216 : app->cb_fns = *a->session_cb_vft;
805 216 : app->ns_index = opts[APP_OPTIONS_NAMESPACE];
806 216 : app->proxied_transports = opts[APP_OPTIONS_PROXY_TRANSPORT];
807 216 : app->name = vec_dup (a->name);
808 :
809 : /* If no scope enabled, default to global */
810 216 : if (!application_has_global_scope (app)
811 47 : && !application_has_local_scope (app))
812 28 : app->flags |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
813 :
814 216 : props = application_segment_manager_properties (app);
815 216 : segment_manager_props_init (props);
816 216 : props->segment_size = opts[APP_OPTIONS_SEGMENT_SIZE];
817 216 : props->prealloc_fifos = opts[APP_OPTIONS_PREALLOC_FIFO_PAIRS];
818 216 : props->prealloc_fifo_hdrs = opts[APP_OPTIONS_PREALLOC_FIFO_HDRS];
819 216 : if (opts[APP_OPTIONS_ADD_SEGMENT_SIZE])
820 : {
821 199 : props->add_segment_size = opts[APP_OPTIONS_ADD_SEGMENT_SIZE];
822 199 : props->add_segment = 1;
823 : }
824 216 : if (opts[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_USE_HUGE_PAGE)
825 0 : props->huge_page = 1;
826 216 : if (opts[APP_OPTIONS_RX_FIFO_SIZE])
827 202 : props->rx_fifo_size = opts[APP_OPTIONS_RX_FIFO_SIZE];
828 216 : if (opts[APP_OPTIONS_TX_FIFO_SIZE])
829 202 : props->tx_fifo_size = opts[APP_OPTIONS_TX_FIFO_SIZE];
830 216 : if (opts[APP_OPTIONS_EVT_QUEUE_SIZE])
831 57 : props->evt_q_size = opts[APP_OPTIONS_EVT_QUEUE_SIZE];
832 216 : if (opts[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD)
833 0 : props->use_mq_eventfd = 1;
834 216 : if (opts[APP_OPTIONS_TLS_ENGINE])
835 68 : app->tls_engine = opts[APP_OPTIONS_TLS_ENGINE];
836 216 : if (opts[APP_OPTIONS_MAX_FIFO_SIZE])
837 0 : props->max_fifo_size = opts[APP_OPTIONS_MAX_FIFO_SIZE];
838 216 : if (opts[APP_OPTIONS_HIGH_WATERMARK])
839 0 : props->high_watermark = opts[APP_OPTIONS_HIGH_WATERMARK];
840 216 : if (opts[APP_OPTIONS_LOW_WATERMARK])
841 0 : props->low_watermark = opts[APP_OPTIONS_LOW_WATERMARK];
842 216 : if (opts[APP_OPTIONS_PCT_FIRST_ALLOC])
843 16 : props->pct_first_alloc = opts[APP_OPTIONS_PCT_FIRST_ALLOC];
844 216 : props->segment_type = seg_type;
845 :
846 : /* Add app to lookup by api_client_index table */
847 216 : if (!application_is_builtin (app))
848 57 : application_api_table_add (app->app_index, a->api_client_index);
849 : else
850 159 : application_name_table_add (app);
851 :
852 216 : a->app_index = app->app_index;
853 :
854 : APP_DBG ("New app name: %v api index: %u index %u", app->name,
855 : a->api_client_index, app->app_index);
856 :
857 216 : return 0;
858 : }
859 :
860 : static void
861 87 : application_free (application_t * app)
862 : {
863 : app_worker_map_t *wrk_map;
864 : app_worker_t *app_wrk;
865 :
866 : /*
867 : * The app event queue allocated in first segment is cleared with
868 : * the segment manager. No need to explicitly free it.
869 : */
870 : APP_DBG ("Delete app name %v index: %d", app->name, app->app_index);
871 :
872 87 : if (application_is_proxy (app))
873 1 : application_remove_proxy (app);
874 :
875 : /*
876 : * Free workers
877 : */
878 :
879 : /* *INDENT-OFF* */
880 175 : pool_flush (wrk_map, app->worker_maps, ({
881 : app_wrk = app_worker_get (wrk_map->wrk_index);
882 : app_worker_free (app_wrk);
883 : }));
884 : /* *INDENT-ON* */
885 87 : pool_free (app->worker_maps);
886 :
887 : /*
888 : * Free rx mqs if allocated
889 : */
890 87 : if (app->rx_mqs)
891 : {
892 : int i;
893 8 : for (i = 0; i < vec_len (app->rx_mqs); i++)
894 4 : app_rx_mqs_epoll_del (app, &app->rx_mqs[i]);
895 :
896 4 : fifo_segment_cleanup (&app->rx_mqs_segment);
897 4 : ssvm_delete (&app->rx_mqs_segment.ssvm);
898 4 : vec_free (app->rx_mqs);
899 : }
900 :
901 : /*
902 : * Cleanup remaining state
903 : */
904 87 : if (application_is_builtin (app))
905 43 : application_name_table_del (app);
906 87 : vec_free (app->name);
907 87 : pool_put (app_main.app_pool, app);
908 87 : }
909 :
910 : static void
911 66 : application_detach_process (application_t * app, u32 api_client_index)
912 : {
913 66 : vnet_app_worker_add_del_args_t _args = { 0 }, *args = &_args;
914 : app_worker_map_t *wrk_map;
915 66 : u32 *wrks = 0, *wrk_index;
916 : app_worker_t *app_wrk;
917 :
918 66 : if (api_client_index == ~0)
919 : {
920 44 : application_free (app);
921 44 : return;
922 : }
923 :
924 : APP_DBG ("Detaching for app %v index %u api client index %u", app->name,
925 : app->app_index, api_client_index);
926 :
927 : /* *INDENT-OFF* */
928 44 : pool_foreach (wrk_map, app->worker_maps) {
929 22 : app_wrk = app_worker_get (wrk_map->wrk_index);
930 22 : if (app_wrk->api_client_index == api_client_index)
931 22 : vec_add1 (wrks, app_wrk->wrk_index);
932 : }
933 : /* *INDENT-ON* */
934 :
935 22 : if (!vec_len (wrks))
936 : {
937 0 : clib_warning ("no workers for app %u api_index %u", app->app_index,
938 : api_client_index);
939 0 : return;
940 : }
941 :
942 22 : args->app_index = app->app_index;
943 22 : args->api_client_index = api_client_index;
944 44 : vec_foreach (wrk_index, wrks)
945 : {
946 22 : app_wrk = app_worker_get (wrk_index[0]);
947 22 : args->wrk_map_index = app_wrk->wrk_map_index;
948 22 : args->is_add = 0;
949 22 : vnet_app_worker_add_del (args);
950 : }
951 22 : vec_free (wrks);
952 : }
953 :
954 : void
955 3 : application_namespace_cleanup (app_namespace_t *app_ns)
956 : {
957 3 : u32 *app_indices = 0, *app_index;
958 : application_t *app;
959 : u32 ns_index;
960 :
961 3 : ns_index = app_namespace_index (app_ns);
962 9 : pool_foreach (app, app_main.app_pool)
963 6 : if (app->ns_index == ns_index)
964 0 : vec_add1 (app_indices, app->ns_index);
965 :
966 3 : vec_foreach (app_index, app_indices)
967 : {
968 0 : app = application_get (*app_index);
969 :
970 0 : if (application_is_proxy (app))
971 0 : application_remove_proxy (app);
972 0 : app->flags &= ~APP_OPTIONS_FLAGS_IS_PROXY;
973 :
974 0 : application_free (app);
975 : }
976 3 : vec_free (app_indices);
977 3 : }
978 :
979 : app_worker_t *
980 627 : application_get_worker (application_t * app, u32 wrk_map_index)
981 : {
982 : app_worker_map_t *map;
983 627 : map = app_worker_map_get (app, wrk_map_index);
984 627 : if (!map)
985 0 : return 0;
986 627 : return app_worker_get (map->wrk_index);
987 : }
988 :
989 : app_worker_t *
990 13 : application_get_default_worker (application_t * app)
991 : {
992 13 : return application_get_worker (app, 0);
993 : }
994 :
995 : u32
996 43 : application_n_workers (application_t * app)
997 : {
998 43 : return pool_elts (app->worker_maps);
999 : }
1000 :
1001 : app_worker_t *
1002 189 : application_listener_select_worker (session_t * ls)
1003 : {
1004 : application_t *app;
1005 : app_listener_t *al;
1006 :
1007 189 : app = application_get (ls->app_index);
1008 189 : al = app_listener_get (app, ls->al_index);
1009 189 : return app_listener_select_worker (app, al);
1010 : }
1011 :
1012 : int
1013 216 : application_alloc_worker_and_init (application_t * app, app_worker_t ** wrk)
1014 : {
1015 : app_worker_map_t *wrk_map;
1016 : app_worker_t *app_wrk;
1017 : segment_manager_t *sm;
1018 : int rv;
1019 :
1020 216 : app_wrk = app_worker_alloc (app);
1021 216 : wrk_map = app_worker_map_alloc (app);
1022 216 : wrk_map->wrk_index = app_wrk->wrk_index;
1023 216 : app_wrk->wrk_map_index = app_worker_map_index (app, wrk_map);
1024 :
1025 : /*
1026 : * Setup first segment manager
1027 : */
1028 216 : sm = segment_manager_alloc ();
1029 216 : sm->app_wrk_index = app_wrk->wrk_index;
1030 :
1031 216 : if ((rv = segment_manager_init_first (sm)))
1032 : {
1033 0 : app_worker_free (app_wrk);
1034 0 : return rv;
1035 : }
1036 216 : sm->first_is_protected = 1;
1037 :
1038 : /*
1039 : * Setup app worker
1040 : */
1041 216 : app_wrk->connects_seg_manager = segment_manager_index (sm);
1042 216 : app_wrk->listeners_table = hash_create (0, sizeof (u64));
1043 216 : app_wrk->event_queue = segment_manager_event_queue (sm);
1044 216 : app_wrk->app_is_builtin = application_is_builtin (app);
1045 :
1046 216 : *wrk = app_wrk;
1047 :
1048 216 : return 0;
1049 : }
1050 :
1051 : int
1052 43 : vnet_app_worker_add_del (vnet_app_worker_add_del_args_t * a)
1053 : {
1054 : fifo_segment_t *fs;
1055 : app_worker_map_t *wrk_map;
1056 : app_worker_t *app_wrk;
1057 : segment_manager_t *sm;
1058 : application_t *app;
1059 : int rv;
1060 :
1061 43 : app = application_get (a->app_index);
1062 43 : if (!app)
1063 0 : return VNET_API_ERROR_INVALID_VALUE;
1064 :
1065 43 : if (a->is_add)
1066 : {
1067 0 : if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
1068 0 : return rv;
1069 :
1070 : /* Map worker api index to the app */
1071 0 : app_wrk->api_client_index = a->api_client_index;
1072 0 : application_api_table_add (app->app_index, a->api_client_index);
1073 :
1074 0 : sm = segment_manager_get (app_wrk->connects_seg_manager);
1075 0 : fs = segment_manager_get_segment_w_lock (sm, 0);
1076 0 : a->segment = &fs->ssvm;
1077 0 : a->segment_handle = segment_manager_segment_handle (sm, fs);
1078 0 : segment_manager_segment_reader_unlock (sm);
1079 0 : a->evt_q = app_wrk->event_queue;
1080 0 : a->wrk_map_index = app_wrk->wrk_map_index;
1081 : }
1082 : else
1083 : {
1084 43 : wrk_map = app_worker_map_get (app, a->wrk_map_index);
1085 43 : if (!wrk_map)
1086 0 : return VNET_API_ERROR_INVALID_VALUE;
1087 :
1088 43 : app_wrk = app_worker_get (wrk_map->wrk_index);
1089 43 : if (!app_wrk)
1090 0 : return VNET_API_ERROR_INVALID_VALUE;
1091 :
1092 43 : application_api_table_del (app_wrk->api_client_index);
1093 43 : if (appns_sapi_enabled ())
1094 14 : sapi_socket_close_w_handle (app_wrk->api_client_index);
1095 43 : app_worker_free (app_wrk);
1096 43 : app_worker_map_free (app, wrk_map);
1097 43 : if (application_n_workers (app) == 0)
1098 43 : application_free (app);
1099 : }
1100 43 : return 0;
1101 : }
1102 :
1103 : static int
1104 203 : app_validate_namespace (u8 * namespace_id, u64 secret, u32 * app_ns_index)
1105 : {
1106 : app_namespace_t *app_ns;
1107 203 : if (vec_len (namespace_id) == 0)
1108 : {
1109 : /* Use default namespace */
1110 149 : *app_ns_index = 0;
1111 149 : return 0;
1112 : }
1113 :
1114 54 : *app_ns_index = app_namespace_index_from_id (namespace_id);
1115 54 : if (*app_ns_index == APP_NAMESPACE_INVALID_INDEX)
1116 0 : return VNET_API_ERROR_APP_INVALID_NS;
1117 54 : app_ns = app_namespace_get (*app_ns_index);
1118 54 : if (!app_ns)
1119 0 : return VNET_API_ERROR_APP_INVALID_NS;
1120 54 : if (app_ns->ns_secret != secret)
1121 1 : return VNET_API_ERROR_APP_WRONG_NS_SECRET;
1122 53 : return 0;
1123 : }
1124 :
1125 : static u8 *
1126 43 : app_name_from_api_index (u32 api_client_index)
1127 : {
1128 : vl_api_registration_t *regp;
1129 43 : regp = vl_api_client_index_to_registration (api_client_index);
1130 43 : if (regp)
1131 43 : return format (0, "%s", regp->name);
1132 :
1133 0 : clib_warning ("api client index %u does not have an api registration!",
1134 : api_client_index);
1135 0 : return format (0, "unknown");
1136 : }
1137 :
1138 : /**
1139 : * Attach application to vpp
1140 : *
1141 : * Allocates a vpp app, i.e., a structure that keeps back pointers
1142 : * to external app and a segment manager for shared memory fifo based
1143 : * communication with the external app.
1144 : */
1145 : int
1146 217 : vnet_application_attach (vnet_app_attach_args_t * a)
1147 : {
1148 : fifo_segment_t *fs;
1149 217 : application_t *app = 0;
1150 : app_worker_t *app_wrk;
1151 : segment_manager_t *sm;
1152 217 : u32 app_ns_index = 0;
1153 217 : u8 *app_name = 0;
1154 : u64 secret;
1155 : int rv;
1156 :
1157 217 : if (a->api_client_index != APP_INVALID_INDEX)
1158 57 : app = application_lookup (a->api_client_index);
1159 160 : else if (a->name)
1160 160 : app = application_lookup_name (a->name);
1161 : else
1162 0 : return VNET_API_ERROR_INVALID_VALUE;
1163 :
1164 217 : if (app)
1165 0 : return VNET_API_ERROR_APP_ALREADY_ATTACHED;
1166 :
1167 : /* Socket api sets the name and validates namespace prior to attach */
1168 217 : if (!a->use_sock_api)
1169 : {
1170 203 : if (a->api_client_index != APP_INVALID_INDEX)
1171 : {
1172 43 : app_name = app_name_from_api_index (a->api_client_index);
1173 43 : a->name = app_name;
1174 : }
1175 :
1176 203 : secret = a->options[APP_OPTIONS_NAMESPACE_SECRET];
1177 203 : if ((rv = app_validate_namespace (a->namespace_id, secret,
1178 : &app_ns_index)))
1179 1 : return rv;
1180 202 : a->options[APP_OPTIONS_NAMESPACE] = app_ns_index;
1181 : }
1182 :
1183 216 : if ((rv = application_alloc_and_init ((app_init_args_t *) a)))
1184 0 : return rv;
1185 :
1186 216 : app = application_get (a->app_index);
1187 216 : if ((rv = application_alloc_worker_and_init (app, &app_wrk)))
1188 0 : return rv;
1189 :
1190 216 : a->app_evt_q = app_wrk->event_queue;
1191 216 : app_wrk->api_client_index = a->api_client_index;
1192 216 : sm = segment_manager_get (app_wrk->connects_seg_manager);
1193 216 : fs = segment_manager_get_segment_w_lock (sm, 0);
1194 :
1195 216 : if (application_is_proxy (app))
1196 : {
1197 1 : application_setup_proxy (app);
1198 : /* The segment manager pool is reallocated because a new listener
1199 : * is added. Re-grab segment manager to avoid dangling reference */
1200 1 : sm = segment_manager_get (app_wrk->connects_seg_manager);
1201 : }
1202 :
1203 216 : ASSERT (vec_len (fs->ssvm.name) <= 128);
1204 216 : a->segment = &fs->ssvm;
1205 216 : a->segment_handle = segment_manager_segment_handle (sm, fs);
1206 :
1207 216 : segment_manager_segment_reader_unlock (sm);
1208 :
1209 216 : if (!application_is_builtin (app) && application_use_private_rx_mqs ())
1210 4 : rv = app_rx_mqs_alloc (app);
1211 :
1212 216 : vec_free (app_name);
1213 216 : return rv;
1214 : }
1215 :
1216 : /**
1217 : * Detach application from vpp
1218 : */
1219 : int
1220 66 : vnet_application_detach (vnet_app_detach_args_t * a)
1221 : {
1222 : application_t *app;
1223 :
1224 66 : app = application_get_if_valid (a->app_index);
1225 66 : if (!app)
1226 : {
1227 0 : clib_warning ("app not attached");
1228 0 : return VNET_API_ERROR_APPLICATION_NOT_ATTACHED;
1229 : }
1230 :
1231 66 : app_interface_check_thread_and_barrier (vnet_application_detach, a);
1232 66 : application_detach_process (app, a->api_client_index);
1233 66 : return 0;
1234 : }
1235 :
1236 : static u8
1237 73 : session_endpoint_in_ns (session_endpoint_cfg_t *sep)
1238 : {
1239 : u8 is_lep;
1240 :
1241 73 : if (sep->flags & SESSION_ENDPT_CFG_F_PROXY_LISTEN)
1242 0 : return 1;
1243 :
1244 73 : is_lep = session_endpoint_is_local ((session_endpoint_t *) sep);
1245 73 : if (!is_lep && sep->sw_if_index != ENDPOINT_INVALID_INDEX
1246 13 : && !ip_interface_has_address (sep->sw_if_index, &sep->ip, sep->is_ip4))
1247 : {
1248 0 : clib_warning ("sw_if_index %u not configured with ip %U",
1249 : sep->sw_if_index, format_ip46_address, &sep->ip,
1250 : sep->is_ip4);
1251 0 : return 0;
1252 : }
1253 :
1254 73 : return (is_lep || ip_is_local (sep->fib_index, &sep->ip, sep->is_ip4));
1255 : }
1256 :
1257 : static void
1258 286 : session_endpoint_update_for_app (session_endpoint_cfg_t * sep,
1259 : application_t * app, u8 is_connect)
1260 : {
1261 : app_namespace_t *app_ns;
1262 : u32 ns_index, fib_index;
1263 :
1264 286 : ns_index = app->ns_index;
1265 :
1266 : /* App is a transport proto, so fetch the calling app's ns */
1267 286 : if (app->flags & APP_OPTIONS_FLAGS_IS_TRANSPORT_APP)
1268 32 : ns_index = sep->ns_index;
1269 :
1270 286 : app_ns = app_namespace_get (ns_index);
1271 286 : if (!app_ns)
1272 0 : return;
1273 :
1274 : /* Ask transport and network to bind to/connect using local interface
1275 : * that "supports" app's namespace. This will fix our local connection
1276 : * endpoint.
1277 : */
1278 :
1279 : /* If in default namespace and user requested a fib index use it */
1280 286 : if (ns_index == 0 && sep->fib_index != ENDPOINT_INVALID_INDEX)
1281 34 : fib_index = sep->fib_index;
1282 : else
1283 252 : fib_index = sep->is_ip4 ? app_ns->ip4_fib_index : app_ns->ip6_fib_index;
1284 286 : sep->peer.fib_index = fib_index;
1285 286 : sep->fib_index = fib_index;
1286 :
1287 286 : if (!is_connect)
1288 : {
1289 73 : sep->sw_if_index = app_ns->sw_if_index;
1290 : }
1291 : else
1292 : {
1293 213 : if (app_ns->sw_if_index != APP_NAMESPACE_INVALID_INDEX
1294 195 : && sep->peer.sw_if_index != ENDPOINT_INVALID_INDEX
1295 129 : && sep->peer.sw_if_index != app_ns->sw_if_index)
1296 0 : clib_warning ("Local sw_if_index different from app ns sw_if_index");
1297 :
1298 213 : sep->peer.sw_if_index = app_ns->sw_if_index;
1299 : }
1300 : }
1301 :
1302 : int
1303 73 : vnet_listen (vnet_listen_args_t * a)
1304 : {
1305 : app_listener_t *app_listener;
1306 : app_worker_t *app_wrk;
1307 : application_t *app;
1308 : int rv;
1309 :
1310 73 : ASSERT (vlib_thread_is_main_w_barrier ());
1311 :
1312 73 : app = application_get_if_valid (a->app_index);
1313 73 : if (!app)
1314 0 : return SESSION_E_NOAPP;
1315 :
1316 73 : app_wrk = application_get_worker (app, a->wrk_map_index);
1317 73 : if (!app_wrk)
1318 0 : return SESSION_E_INVALID_APPWRK;
1319 :
1320 73 : a->sep_ext.app_wrk_index = app_wrk->wrk_index;
1321 :
1322 73 : session_endpoint_update_for_app (&a->sep_ext, app, 0 /* is_connect */ );
1323 73 : if (!session_endpoint_in_ns (&a->sep_ext))
1324 0 : return SESSION_E_INVALID_NS;
1325 :
1326 : /*
1327 : * Check if we already have an app listener
1328 : */
1329 73 : app_listener = app_listener_lookup (app, &a->sep_ext);
1330 73 : if (app_listener)
1331 : {
1332 2 : if (app_listener->app_index != app->app_index)
1333 0 : return SESSION_E_ALREADY_LISTENING;
1334 2 : if ((rv = app_worker_start_listen (app_wrk, app_listener)))
1335 2 : return rv;
1336 0 : a->handle = app_listener_handle (app_listener);
1337 0 : return 0;
1338 : }
1339 :
1340 : /*
1341 : * Create new app listener
1342 : */
1343 71 : if ((rv = app_listener_alloc_and_init (app, &a->sep_ext, &app_listener)))
1344 0 : return rv;
1345 :
1346 71 : if ((rv = app_worker_start_listen (app_wrk, app_listener)))
1347 : {
1348 0 : app_listener_cleanup (app_listener);
1349 0 : return rv;
1350 : }
1351 :
1352 71 : a->handle = app_listener_handle (app_listener);
1353 71 : return 0;
1354 : }
1355 :
1356 : int
1357 214 : vnet_connect (vnet_connect_args_t * a)
1358 : {
1359 : app_worker_t *client_wrk;
1360 : application_t *client;
1361 :
1362 214 : ASSERT (session_vlib_thread_is_cl_thread ());
1363 :
1364 214 : if (session_endpoint_is_zero (&a->sep))
1365 1 : return SESSION_E_INVALID_RMT_IP;
1366 :
1367 213 : client = application_get (a->app_index);
1368 213 : session_endpoint_update_for_app (&a->sep_ext, client, 1 /* is_connect */ );
1369 213 : client_wrk = application_get_worker (client, a->wrk_map_index);
1370 :
1371 213 : a->sep_ext.opaque = a->api_context;
1372 :
1373 : /*
1374 : * First check the local scope for locally attached destinations.
1375 : * If we have local scope, we pass *all* connects through it since we may
1376 : * have special policy rules even for non-local destinations, think proxy.
1377 : */
1378 213 : if (application_has_local_scope (client))
1379 : {
1380 : int rv;
1381 :
1382 17 : a->sep_ext.original_tp = a->sep_ext.transport_proto;
1383 17 : a->sep_ext.transport_proto = TRANSPORT_PROTO_NONE;
1384 17 : rv = app_worker_connect_session (client_wrk, &a->sep_ext, &a->sh);
1385 17 : a->sep_ext.transport_proto = a->sep_ext.original_tp;
1386 17 : if (!rv || rv != SESSION_E_LOCAL_CONNECT)
1387 17 : return rv;
1388 : }
1389 : /*
1390 : * Not connecting to a local server, propagate to transport
1391 : */
1392 196 : return app_worker_connect_session (client_wrk, &a->sep_ext, &a->sh);
1393 : }
1394 :
1395 : int
1396 59 : vnet_unlisten (vnet_unlisten_args_t * a)
1397 : {
1398 : app_worker_t *app_wrk;
1399 : app_listener_t *al;
1400 : application_t *app;
1401 :
1402 59 : ASSERT (vlib_thread_is_main_w_barrier ());
1403 :
1404 59 : if (!(app = application_get_if_valid (a->app_index)))
1405 0 : return SESSION_E_NOAPP;
1406 :
1407 59 : if (!(al = app_listener_get_w_handle (a->handle)))
1408 2 : return SESSION_E_NOLISTEN;
1409 :
1410 57 : if (al->app_index != app->app_index)
1411 : {
1412 0 : clib_warning ("app doesn't own handle %llu!", a->handle);
1413 0 : return SESSION_E_OWNER;
1414 : }
1415 :
1416 57 : app_wrk = application_get_worker (app, a->wrk_map_index);
1417 57 : if (!app_wrk)
1418 : {
1419 0 : clib_warning ("no app %u worker %u", app->app_index, a->wrk_map_index);
1420 0 : return SESSION_E_INVALID_APPWRK;
1421 : }
1422 :
1423 57 : return app_worker_stop_listen (app_wrk, al);
1424 : }
1425 :
1426 : int
1427 0 : vnet_shutdown_session (vnet_shutdown_args_t *a)
1428 : {
1429 : app_worker_t *app_wrk;
1430 : session_t *s;
1431 :
1432 0 : s = session_get_from_handle_if_valid (a->handle);
1433 0 : if (!s)
1434 0 : return SESSION_E_NOSESSION;
1435 :
1436 0 : app_wrk = app_worker_get (s->app_wrk_index);
1437 0 : if (app_wrk->app_index != a->app_index)
1438 0 : return SESSION_E_OWNER;
1439 :
1440 : /* We're peeking into another's thread pool. Make sure */
1441 0 : ASSERT (s->session_index == session_index_from_handle (a->handle));
1442 :
1443 0 : session_half_close (s);
1444 0 : return 0;
1445 : }
1446 :
1447 : int
1448 355 : vnet_disconnect_session (vnet_disconnect_args_t * a)
1449 : {
1450 : app_worker_t *app_wrk;
1451 : session_t *s;
1452 :
1453 355 : s = session_get_from_handle_if_valid (a->handle);
1454 355 : if (!s)
1455 0 : return SESSION_E_NOSESSION;
1456 :
1457 355 : app_wrk = app_worker_get (s->app_wrk_index);
1458 355 : if (app_wrk->app_index != a->app_index)
1459 0 : return SESSION_E_OWNER;
1460 :
1461 : /* We're peeking into another's thread pool. Make sure */
1462 355 : ASSERT (s->session_index == session_index_from_handle (a->handle));
1463 :
1464 355 : session_close (s);
1465 355 : return 0;
1466 : }
1467 :
1468 : int
1469 0 : application_change_listener_owner (session_t * s, app_worker_t * app_wrk)
1470 : {
1471 0 : app_worker_t *old_wrk = app_worker_get (s->app_wrk_index);
1472 : app_listener_t *app_listener;
1473 : application_t *app;
1474 : int rv;
1475 :
1476 0 : if (!old_wrk)
1477 0 : return SESSION_E_INVALID_APPWRK;
1478 :
1479 0 : hash_unset (old_wrk->listeners_table, listen_session_get_handle (s));
1480 0 : if (session_transport_service_type (s) == TRANSPORT_SERVICE_CL
1481 0 : && s->rx_fifo)
1482 0 : segment_manager_dealloc_fifos (s->rx_fifo, s->tx_fifo);
1483 :
1484 0 : app = application_get (old_wrk->app_index);
1485 0 : if (!app)
1486 0 : return SESSION_E_NOAPP;
1487 :
1488 0 : app_listener = app_listener_get (app, s->al_index);
1489 :
1490 : /* Only remove from lb for now */
1491 0 : app_listener->workers = clib_bitmap_set (app_listener->workers,
1492 0 : old_wrk->wrk_map_index, 0);
1493 :
1494 0 : if ((rv = app_worker_start_listen (app_wrk, app_listener)))
1495 0 : return rv;
1496 :
1497 0 : s->app_wrk_index = app_wrk->wrk_index;
1498 :
1499 0 : return 0;
1500 : }
1501 :
1502 : int
1503 565 : application_is_proxy (application_t * app)
1504 : {
1505 565 : return (app->flags & APP_OPTIONS_FLAGS_IS_PROXY);
1506 : }
1507 :
1508 : int
1509 735 : application_is_builtin (application_t * app)
1510 : {
1511 735 : return (app->flags & APP_OPTIONS_FLAGS_IS_BUILTIN);
1512 : }
1513 :
1514 : int
1515 225 : application_is_builtin_proxy (application_t * app)
1516 : {
1517 225 : return (application_is_proxy (app) && application_is_builtin (app));
1518 : }
1519 :
1520 : u8
1521 556 : application_has_local_scope (application_t * app)
1522 : {
1523 556 : return app->flags & APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1524 : }
1525 :
1526 : u8
1527 295 : application_has_global_scope (application_t * app)
1528 : {
1529 295 : return app->flags & APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1530 : }
1531 :
1532 : static clib_error_t *
1533 4 : application_start_stop_proxy_fib_proto (application_t * app, u8 fib_proto,
1534 : u8 transport_proto, u8 is_start)
1535 : {
1536 4 : app_namespace_t *app_ns = app_namespace_get (app->ns_index);
1537 4 : u8 is_ip4 = (fib_proto == FIB_PROTOCOL_IP4);
1538 4 : session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
1539 : transport_connection_t *tc;
1540 : app_worker_t *app_wrk;
1541 : app_listener_t *al;
1542 : session_t *s;
1543 : u32 flags;
1544 :
1545 : /* TODO decide if we want proxy to be enabled for all workers */
1546 4 : app_wrk = application_get_default_worker (app);
1547 4 : if (is_start)
1548 : {
1549 2 : s = app_worker_first_listener (app_wrk, fib_proto, transport_proto);
1550 2 : if (!s)
1551 : {
1552 2 : sep.is_ip4 = is_ip4;
1553 2 : sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1554 2 : sep.sw_if_index = app_ns->sw_if_index;
1555 2 : sep.transport_proto = transport_proto;
1556 2 : sep.app_wrk_index = app_wrk->wrk_index; /* only default */
1557 :
1558 : /* force global scope listener */
1559 2 : flags = app->flags;
1560 2 : app->flags &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1561 2 : app_listener_alloc_and_init (app, &sep, &al);
1562 2 : app->flags = flags;
1563 :
1564 2 : app_worker_start_listen (app_wrk, al);
1565 2 : s = listen_session_get (al->session_index);
1566 2 : s->flags |= SESSION_F_PROXY;
1567 : }
1568 : }
1569 : else
1570 : {
1571 2 : s = app_worker_proxy_listener (app_wrk, fib_proto, transport_proto);
1572 2 : ASSERT (s);
1573 : }
1574 :
1575 4 : tc = listen_session_get_transport (s);
1576 :
1577 4 : if (!ip_is_zero (&tc->lcl_ip, 1))
1578 : {
1579 : u32 sti;
1580 2 : sep.is_ip4 = is_ip4;
1581 2 : sep.fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
1582 2 : sep.transport_proto = transport_proto;
1583 2 : sep.port = 0;
1584 2 : sti = session_lookup_get_index_for_fib (fib_proto, sep.fib_index);
1585 2 : if (is_start)
1586 1 : session_lookup_add_session_endpoint (sti,
1587 : (session_endpoint_t *) & sep,
1588 1 : s->session_index);
1589 : else
1590 1 : session_lookup_del_session_endpoint (sti,
1591 : (session_endpoint_t *) & sep);
1592 : }
1593 :
1594 4 : return 0;
1595 : }
1596 :
1597 : static void
1598 2 : application_start_stop_proxy_local_scope (application_t * app,
1599 : u8 transport_proto, u8 is_start)
1600 : {
1601 2 : session_endpoint_t sep = SESSION_ENDPOINT_NULL;
1602 : app_namespace_t *app_ns;
1603 2 : app_ns = app_namespace_get (app->ns_index);
1604 2 : sep.is_ip4 = 1;
1605 2 : sep.transport_proto = transport_proto;
1606 2 : sep.port = 0;
1607 :
1608 2 : if (is_start)
1609 : {
1610 1 : session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
1611 1 : app->app_index);
1612 1 : sep.is_ip4 = 0;
1613 1 : session_lookup_add_session_endpoint (app_ns->local_table_index, &sep,
1614 1 : app->app_index);
1615 : }
1616 : else
1617 : {
1618 1 : session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1619 1 : sep.is_ip4 = 0;
1620 1 : session_lookup_del_session_endpoint (app_ns->local_table_index, &sep);
1621 : }
1622 2 : }
1623 :
1624 : void
1625 2 : application_start_stop_proxy (application_t * app,
1626 : transport_proto_t transport_proto, u8 is_start)
1627 : {
1628 2 : if (application_has_local_scope (app))
1629 2 : application_start_stop_proxy_local_scope (app, transport_proto, is_start);
1630 :
1631 2 : if (application_has_global_scope (app))
1632 : {
1633 2 : application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP4,
1634 : transport_proto, is_start);
1635 2 : application_start_stop_proxy_fib_proto (app, FIB_PROTOCOL_IP6,
1636 : transport_proto, is_start);
1637 : }
1638 2 : }
1639 :
1640 : void
1641 1 : application_setup_proxy (application_t * app)
1642 : {
1643 1 : u16 transports = app->proxied_transports;
1644 : transport_proto_t tp;
1645 :
1646 1 : ASSERT (application_is_proxy (app));
1647 :
1648 9 : transport_proto_foreach (tp, transports)
1649 1 : application_start_stop_proxy (app, tp, 1);
1650 1 : }
1651 :
1652 : void
1653 1 : application_remove_proxy (application_t * app)
1654 : {
1655 1 : u16 transports = app->proxied_transports;
1656 : transport_proto_t tp;
1657 :
1658 1 : ASSERT (application_is_proxy (app));
1659 :
1660 9 : transport_proto_foreach (tp, transports)
1661 1 : application_start_stop_proxy (app, tp, 0);
1662 1 : }
1663 :
1664 : segment_manager_props_t *
1665 242 : application_segment_manager_properties (application_t * app)
1666 : {
1667 242 : return &app->sm_properties;
1668 : }
1669 :
1670 : segment_manager_props_t *
1671 1219 : application_get_segment_manager_properties (u32 app_index)
1672 : {
1673 1219 : application_t *app = application_get (app_index);
1674 1219 : return &app->sm_properties;
1675 : }
1676 :
1677 : static void
1678 15 : application_format_listeners (application_t * app, int verbose)
1679 : {
1680 15 : vlib_main_t *vm = vlib_get_main ();
1681 : app_worker_map_t *wrk_map;
1682 : app_worker_t *app_wrk;
1683 : u32 sm_index;
1684 : u64 handle;
1685 :
1686 15 : if (!app)
1687 : {
1688 5 : vlib_cli_output (vm, "%U", format_app_worker_listener, NULL /* header */,
1689 : 0, 0, verbose);
1690 5 : return;
1691 : }
1692 :
1693 : /* *INDENT-OFF* */
1694 20 : pool_foreach (wrk_map, app->worker_maps) {
1695 10 : app_wrk = app_worker_get (wrk_map->wrk_index);
1696 10 : if (hash_elts (app_wrk->listeners_table) == 0)
1697 10 : continue;
1698 10 : hash_foreach (handle, sm_index, app_wrk->listeners_table, ({
1699 : vlib_cli_output (vm, "%U", format_app_worker_listener, app_wrk,
1700 : handle, sm_index, verbose);
1701 : }));
1702 : }
1703 : /* *INDENT-ON* */
1704 : }
1705 :
1706 : static void
1707 0 : application_format_connects (application_t * app, int verbose)
1708 : {
1709 : app_worker_map_t *wrk_map;
1710 : app_worker_t *app_wrk;
1711 :
1712 0 : if (!app)
1713 : {
1714 0 : app_worker_format_connects (0, verbose);
1715 0 : return;
1716 : }
1717 :
1718 : /* *INDENT-OFF* */
1719 0 : pool_foreach (wrk_map, app->worker_maps) {
1720 0 : app_wrk = app_worker_get (wrk_map->wrk_index);
1721 0 : app_worker_format_connects (app_wrk, verbose);
1722 : }
1723 : /* *INDENT-ON* */
1724 : }
1725 :
1726 : u8 *
1727 0 : format_cert_key_pair (u8 * s, va_list * args)
1728 : {
1729 0 : app_cert_key_pair_t *ckpair = va_arg (*args, app_cert_key_pair_t *);
1730 0 : int key_len = 0, cert_len = 0;
1731 0 : cert_len = vec_len (ckpair->cert);
1732 0 : key_len = vec_len (ckpair->key);
1733 0 : if (ckpair->cert_key_index == 0)
1734 0 : s = format (s, "DEFAULT (cert:%d, key:%d)", cert_len, key_len);
1735 : else
1736 0 : s = format (s, "%d (cert:%d, key:%d)", ckpair->cert_key_index,
1737 : cert_len, key_len);
1738 0 : return s;
1739 : }
1740 :
1741 : u8 *
1742 0 : format_crypto_engine (u8 * s, va_list * args)
1743 : {
1744 0 : u32 engine = va_arg (*args, u32);
1745 0 : switch (engine)
1746 : {
1747 0 : case CRYPTO_ENGINE_NONE:
1748 0 : return format (s, "none");
1749 0 : case CRYPTO_ENGINE_MBEDTLS:
1750 0 : return format (s, "mbedtls");
1751 0 : case CRYPTO_ENGINE_OPENSSL:
1752 0 : return format (s, "openssl");
1753 0 : case CRYPTO_ENGINE_PICOTLS:
1754 0 : return format (s, "picotls");
1755 0 : case CRYPTO_ENGINE_VPP:
1756 0 : return format (s, "vpp");
1757 0 : default:
1758 0 : return format (s, "unknown engine");
1759 : }
1760 : return s;
1761 : }
1762 :
1763 : uword
1764 0 : unformat_crypto_engine (unformat_input_t * input, va_list * args)
1765 : {
1766 0 : u8 *a = va_arg (*args, u8 *);
1767 0 : if (unformat (input, "mbedtls"))
1768 0 : *a = CRYPTO_ENGINE_MBEDTLS;
1769 0 : else if (unformat (input, "openssl"))
1770 0 : *a = CRYPTO_ENGINE_OPENSSL;
1771 0 : else if (unformat (input, "picotls"))
1772 0 : *a = CRYPTO_ENGINE_PICOTLS;
1773 0 : else if (unformat (input, "vpp"))
1774 0 : *a = CRYPTO_ENGINE_VPP;
1775 : else
1776 0 : return 0;
1777 0 : return 1;
1778 : }
1779 :
1780 : u8 *
1781 0 : format_crypto_context (u8 * s, va_list * args)
1782 : {
1783 0 : crypto_context_t *crctx = va_arg (*args, crypto_context_t *);
1784 0 : s = format (s, "[0x%x][sub%d,ckpair%x]", crctx->ctx_index,
1785 : crctx->n_subscribers, crctx->ckpair_index);
1786 0 : s = format (s, "[%U]", format_crypto_engine, crctx->crypto_engine);
1787 0 : return s;
1788 : }
1789 :
1790 : u8 *
1791 0 : format_application (u8 * s, va_list * args)
1792 : {
1793 0 : application_t *app = va_arg (*args, application_t *);
1794 0 : CLIB_UNUSED (int verbose) = va_arg (*args, int);
1795 : segment_manager_props_t *props;
1796 : const u8 *app_ns_name, *app_name;
1797 : app_worker_map_t *wrk_map;
1798 : app_worker_t *app_wrk;
1799 :
1800 0 : if (app == 0)
1801 : {
1802 0 : if (!verbose)
1803 0 : s = format (s, "%-10s%-20s%-40s", "Index", "Name", "Namespace");
1804 0 : return s;
1805 : }
1806 :
1807 0 : app_name = app_get_name (app);
1808 0 : app_ns_name = app_namespace_id_from_index (app->ns_index);
1809 0 : props = application_segment_manager_properties (app);
1810 0 : if (!verbose)
1811 : {
1812 0 : s = format (s, "%-10u%-20v%-40v", app->app_index, app_name,
1813 : app_ns_name);
1814 0 : return s;
1815 : }
1816 :
1817 0 : s = format (s, "app-name %v app-index %u ns-index %u seg-size %U\n",
1818 : app_name, app->app_index, app->ns_index,
1819 : format_memory_size, props->add_segment_size);
1820 0 : s = format (s, "rx-fifo-size %U tx-fifo-size %U workers:\n",
1821 : format_memory_size, props->rx_fifo_size,
1822 : format_memory_size, props->tx_fifo_size);
1823 :
1824 : /* *INDENT-OFF* */
1825 0 : pool_foreach (wrk_map, app->worker_maps) {
1826 0 : app_wrk = app_worker_get (wrk_map->wrk_index);
1827 0 : s = format (s, "%U", format_app_worker, app_wrk);
1828 : }
1829 : /* *INDENT-ON* */
1830 :
1831 0 : return s;
1832 : }
1833 :
1834 : void
1835 5 : application_format_all_listeners (vlib_main_t * vm, int verbose)
1836 : {
1837 : application_t *app;
1838 :
1839 5 : if (!pool_elts (app_main.app_pool))
1840 : {
1841 0 : vlib_cli_output (vm, "No active server bindings");
1842 0 : return;
1843 : }
1844 :
1845 5 : application_format_listeners (0, verbose);
1846 :
1847 : /* *INDENT-OFF* */
1848 15 : pool_foreach (app, app_main.app_pool) {
1849 10 : application_format_listeners (app, verbose);
1850 : }
1851 : /* *INDENT-ON* */
1852 : }
1853 :
1854 : void
1855 0 : application_format_all_clients (vlib_main_t * vm, int verbose)
1856 : {
1857 : application_t *app;
1858 :
1859 0 : if (!pool_elts (app_main.app_pool))
1860 : {
1861 0 : vlib_cli_output (vm, "No active apps");
1862 0 : return;
1863 : }
1864 :
1865 0 : application_format_connects (0, verbose);
1866 :
1867 : /* *INDENT-OFF* */
1868 0 : pool_foreach (app, app_main.app_pool) {
1869 0 : application_format_connects (app, verbose);
1870 : }
1871 : /* *INDENT-ON* */
1872 : }
1873 :
1874 : static clib_error_t *
1875 0 : show_certificate_command_fn (vlib_main_t * vm, unformat_input_t * input,
1876 : vlib_cli_command_t * cmd)
1877 : {
1878 : app_cert_key_pair_t *ckpair;
1879 0 : session_cli_return_if_not_enabled ();
1880 :
1881 : /* *INDENT-OFF* */
1882 0 : pool_foreach (ckpair, app_main.cert_key_pair_store) {
1883 0 : vlib_cli_output (vm, "%U", format_cert_key_pair, ckpair);
1884 : }
1885 : /* *INDENT-ON* */
1886 0 : return 0;
1887 : }
1888 :
1889 : static inline void
1890 44 : appliction_format_app_mq (vlib_main_t * vm, application_t * app)
1891 : {
1892 : app_worker_map_t *map;
1893 : app_worker_t *wrk;
1894 : int i;
1895 :
1896 : /* *INDENT-OFF* */
1897 88 : pool_foreach (map, app->worker_maps) {
1898 44 : wrk = app_worker_get (map->wrk_index);
1899 44 : vlib_cli_output (vm, "[A%d][%d]%U", app->app_index,
1900 : map->wrk_index, format_svm_msg_q,
1901 : wrk->event_queue);
1902 : }
1903 : /* *INDENT-ON* */
1904 :
1905 44 : for (i = 0; i < vec_len (app->rx_mqs); i++)
1906 0 : vlib_cli_output (vm, "[A%d][R%d]%U", app->app_index, i, format_svm_msg_q,
1907 0 : app->rx_mqs[i].mq);
1908 44 : }
1909 :
1910 : static clib_error_t *
1911 16 : appliction_format_all_app_mq (vlib_main_t * vm)
1912 : {
1913 : application_t *app;
1914 : int i, n_threads;
1915 :
1916 16 : n_threads = vlib_get_n_threads ();
1917 :
1918 32 : for (i = 0; i < n_threads; i++)
1919 : {
1920 16 : vlib_cli_output (vm, "[Ctrl%d]%U", i, format_svm_msg_q,
1921 : session_main_get_vpp_event_queue (i));
1922 : }
1923 :
1924 : /* *INDENT-OFF* */
1925 60 : pool_foreach (app, app_main.app_pool) {
1926 44 : appliction_format_app_mq (vm, app);
1927 : }
1928 : /* *INDENT-ON* */
1929 16 : return 0;
1930 : }
1931 :
1932 : static clib_error_t *
1933 21 : show_app_command_fn (vlib_main_t * vm, unformat_input_t * input,
1934 : vlib_cli_command_t * cmd)
1935 : {
1936 21 : int do_server = 0, do_client = 0, do_mq = 0, do_transports = 0;
1937 : application_t *app;
1938 21 : u32 app_index = ~0;
1939 21 : int verbose = 0;
1940 : u8 is_ta;
1941 :
1942 21 : session_cli_return_if_not_enabled ();
1943 :
1944 42 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1945 : {
1946 21 : if (unformat (input, "server"))
1947 5 : do_server = 1;
1948 16 : else if (unformat (input, "client"))
1949 0 : do_client = 1;
1950 16 : else if (unformat (input, "transports"))
1951 0 : do_transports = 1;
1952 16 : else if (unformat (input, "mq"))
1953 16 : do_mq = 1;
1954 0 : else if (unformat (input, "%u", &app_index))
1955 : ;
1956 0 : else if (unformat (input, "verbose"))
1957 0 : verbose = 1;
1958 : else
1959 0 : return clib_error_return (0, "unknown input `%U'",
1960 : format_unformat_error, input);
1961 : }
1962 :
1963 21 : if (do_mq && app_index != ~0)
1964 : {
1965 0 : app = application_get_if_valid (app_index);
1966 0 : if (!app)
1967 0 : return clib_error_return (0, "No app with index %u", app_index);
1968 :
1969 0 : appliction_format_app_mq (vm, app);
1970 0 : return 0;
1971 : }
1972 :
1973 21 : if (do_mq)
1974 : {
1975 16 : appliction_format_all_app_mq (vm);
1976 16 : return 0;
1977 : }
1978 :
1979 5 : if (do_server)
1980 : {
1981 5 : application_format_all_listeners (vm, verbose);
1982 5 : return 0;
1983 : }
1984 :
1985 0 : if (do_client)
1986 : {
1987 0 : application_format_all_clients (vm, verbose);
1988 0 : return 0;
1989 : }
1990 :
1991 0 : if (app_index != ~0)
1992 : {
1993 0 : app = application_get_if_valid (app_index);
1994 0 : if (!app)
1995 0 : return clib_error_return (0, "No app with index %u", app_index);
1996 :
1997 0 : vlib_cli_output (vm, "%U", format_application, app, /* verbose */ 1);
1998 0 : return 0;
1999 : }
2000 :
2001 : /* Print app related info */
2002 0 : if (!do_server && !do_client)
2003 : {
2004 0 : vlib_cli_output (vm, "%U", format_application, 0, 0);
2005 0 : pool_foreach (app, app_main.app_pool) {
2006 0 : is_ta = app->flags & APP_OPTIONS_FLAGS_IS_TRANSPORT_APP;
2007 0 : if ((!do_transports && !is_ta) || (do_transports && is_ta))
2008 0 : vlib_cli_output (vm, "%U", format_application, app, 0);
2009 : }
2010 : }
2011 :
2012 0 : return 0;
2013 : }
2014 :
2015 : /* Certificate store */
2016 :
2017 : static app_cert_key_pair_t *
2018 588 : app_cert_key_pair_alloc ()
2019 : {
2020 : app_cert_key_pair_t *ckpair;
2021 588 : pool_get (app_main.cert_key_pair_store, ckpair);
2022 588 : clib_memset (ckpair, 0, sizeof (*ckpair));
2023 588 : ckpair->cert_key_index = ckpair - app_main.cert_key_pair_store;
2024 588 : return ckpair;
2025 : }
2026 :
2027 : app_cert_key_pair_t *
2028 44 : app_cert_key_pair_get_if_valid (u32 index)
2029 : {
2030 44 : if (pool_is_free_index (app_main.cert_key_pair_store, index))
2031 0 : return 0;
2032 44 : return app_cert_key_pair_get (index);
2033 : }
2034 :
2035 : app_cert_key_pair_t *
2036 44 : app_cert_key_pair_get (u32 index)
2037 : {
2038 44 : return pool_elt_at_index (app_main.cert_key_pair_store, index);
2039 : }
2040 :
2041 : app_cert_key_pair_t *
2042 0 : app_cert_key_pair_get_default ()
2043 : {
2044 : /* To maintain legacy bapi */
2045 0 : return app_cert_key_pair_get (0);
2046 : }
2047 :
2048 : int
2049 29 : vnet_app_add_cert_key_pair (vnet_app_add_cert_key_pair_args_t * a)
2050 : {
2051 29 : app_cert_key_pair_t *ckpair = app_cert_key_pair_alloc ();
2052 29 : vec_validate (ckpair->cert, a->cert_len - 1);
2053 29 : clib_memcpy_fast (ckpair->cert, a->cert, a->cert_len);
2054 29 : vec_validate (ckpair->key, a->key_len - 1);
2055 29 : clib_memcpy_fast (ckpair->key, a->key, a->key_len);
2056 29 : a->index = ckpair->cert_key_index;
2057 29 : return 0;
2058 : }
2059 :
2060 : int
2061 12 : vnet_app_add_cert_key_interest (u32 index, u32 app_index)
2062 : {
2063 : app_cert_key_pair_t *ckpair;
2064 12 : if (!(ckpair = app_cert_key_pair_get_if_valid (index)))
2065 0 : return -1;
2066 12 : if (vec_search (ckpair->app_interests, app_index) != ~0)
2067 0 : vec_add1 (ckpair->app_interests, app_index);
2068 12 : return 0;
2069 : }
2070 :
2071 : int
2072 14 : vnet_app_del_cert_key_pair (u32 index)
2073 : {
2074 : app_cert_key_pair_t *ckpair;
2075 : application_t *app;
2076 : u32 *app_index;
2077 :
2078 14 : if (!(ckpair = app_cert_key_pair_get_if_valid (index)))
2079 0 : return (VNET_API_ERROR_INVALID_VALUE);
2080 :
2081 14 : vec_foreach (app_index, ckpair->app_interests)
2082 : {
2083 0 : if ((app = application_get_if_valid (*app_index))
2084 0 : && app->cb_fns.app_cert_key_pair_delete_callback)
2085 0 : app->cb_fns.app_cert_key_pair_delete_callback (ckpair);
2086 : }
2087 :
2088 14 : vec_free (ckpair->cert);
2089 14 : vec_free (ckpair->key);
2090 14 : pool_put (app_main.cert_key_pair_store, ckpair);
2091 14 : return 0;
2092 : }
2093 :
2094 : clib_error_t *
2095 559 : application_init (vlib_main_t * vm)
2096 : {
2097 559 : app_main_t *am = &app_main;
2098 : u32 n_workers;
2099 :
2100 559 : n_workers = vlib_num_workers ();
2101 :
2102 : /* Index 0 was originally used by legacy apis, maintain as invalid */
2103 559 : (void) app_cert_key_pair_alloc ();
2104 559 : am->last_crypto_engine = CRYPTO_ENGINE_LAST;
2105 559 : am->app_by_name = hash_create_vec (0, sizeof (u8), sizeof (uword));
2106 :
2107 559 : vec_validate (am->wrk, n_workers);
2108 :
2109 559 : return 0;
2110 : }
2111 :
2112 76719 : VLIB_INIT_FUNCTION (application_init);
2113 :
2114 272887 : VLIB_CLI_COMMAND (show_app_command, static) = {
2115 : .path = "show app",
2116 : .short_help = "show app [index] [server|client] [mq] [verbose] "
2117 : "[transports]",
2118 : .function = show_app_command_fn,
2119 : };
2120 :
2121 272887 : VLIB_CLI_COMMAND (show_certificate_command, static) = {
2122 : .path = "show app certificate",
2123 : .short_help = "list app certs and keys present in store",
2124 : .function = show_certificate_command_fn,
2125 : };
2126 :
2127 : crypto_engine_type_t
2128 0 : app_crypto_engine_type_add (void)
2129 : {
2130 0 : return (++app_main.last_crypto_engine);
2131 : }
2132 :
2133 : u8
2134 25 : app_crypto_engine_n_types (void)
2135 : {
2136 25 : return (app_main.last_crypto_engine + 1);
2137 : }
2138 :
2139 : /*
2140 : * fd.io coding-style-patch-verification: ON
2141 : *
2142 : * Local Variables:
2143 : * eval: (c-set-style "gnu")
2144 : * End:
2145 : */
|