blob: b7467bbbd4301a3aeb357a68d78afed3f68411b5 [file] [log] [blame]
Florin Coras6cf30ad2017-04-04 23:08:23 -07001/*
Florin Coras288eaab2019-02-03 15:26:14 -08002 * Copyright (c) 2017-2019 Cisco and/or its affiliates.
Florin Coras6cf30ad2017-04-04 23:08:23 -07003 * 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/segment_manager.h>
17#include <vnet/session/session.h>
18#include <vnet/session/application.h>
19
Florin Corasa332c462018-01-31 06:52:17 -080020segment_manager_main_t segment_manager_main;
21
Florin Coras6cf30ad2017-04-04 23:08:23 -070022/**
23 * Counter used to build segment names
24 */
Florin Corasa332c462018-01-31 06:52:17 -080025static u32 segment_name_counter = 0;
Florin Corasa5464812017-04-19 13:00:05 -070026
27/**
Florin Coras6cf30ad2017-04-04 23:08:23 -070028 * Default fifo and segment size. TODO config.
29 */
Florin Corasf8f516a2018-02-08 15:10:09 -080030static u32 default_fifo_size = 1 << 12;
31static u32 default_segment_size = 1 << 20;
32static u32 default_app_evt_queue_size = 128;
Florin Coras6cf30ad2017-04-04 23:08:23 -070033
Florin Corasad0c77f2017-11-09 18:00:15 -080034segment_manager_properties_t *
Florin Corasa332c462018-01-31 06:52:17 -080035segment_manager_properties_get (segment_manager_t * sm)
Florin Corasad0c77f2017-11-09 18:00:15 -080036{
Florin Corasab2f6db2018-08-31 14:31:41 -070037 app_worker_t *app_wrk = app_worker_get (sm->app_wrk_index);
38 return application_get_segment_manager_properties (app_wrk->app_index);
Florin Corasa332c462018-01-31 06:52:17 -080039}
40
41segment_manager_properties_t *
42segment_manager_properties_init (segment_manager_properties_t * props)
43{
Florin Corasb384b542018-01-15 01:08:33 -080044 props->add_segment_size = default_segment_size;
45 props->rx_fifo_size = default_fifo_size;
46 props->tx_fifo_size = default_fifo_size;
Florin Corasf8f516a2018-02-08 15:10:09 -080047 props->evt_q_size = default_app_evt_queue_size;
Florin Corasad0c77f2017-11-09 18:00:15 -080048 return props;
49}
50
Florin Coras9d063042017-09-14 03:08:00 -040051static u8
52segment_manager_app_detached (segment_manager_t * sm)
53{
Florin Coras15531972018-08-12 23:50:53 -070054 return (sm->app_wrk_index == SEGMENT_MANAGER_INVALID_APP_INDEX);
Dave Wallace7b749fe2017-07-05 14:30:46 -040055}
56
Florin Coras4e4531e2017-11-06 23:27:56 -080057void
58segment_manager_app_detach (segment_manager_t * sm)
59{
Florin Coras15531972018-08-12 23:50:53 -070060 sm->app_wrk_index = SEGMENT_MANAGER_INVALID_APP_INDEX;
Florin Coras4e4531e2017-11-06 23:27:56 -080061}
62
Florin Corasa332c462018-01-31 06:52:17 -080063always_inline u32
64segment_manager_segment_index (segment_manager_t * sm,
65 svm_fifo_segment_private_t * seg)
Florin Corasc87c91d2017-08-16 19:55:49 -070066{
Florin Corasa332c462018-01-31 06:52:17 -080067 return (seg - sm->segments);
68}
69
70/**
71 * Remove segment without lock
72 */
Florin Corasf8f516a2018-02-08 15:10:09 -080073void
Florin Corasa332c462018-01-31 06:52:17 -080074segment_manager_del_segment (segment_manager_t * sm,
75 svm_fifo_segment_private_t * fs)
76{
77 segment_manager_main_t *smm = &segment_manager_main;
78
79 if (ssvm_type (&fs->ssvm) != SSVM_SEGMENT_PRIVATE)
Florin Corasa0dbf9e2019-03-01 17:12:02 -080080 {
81 clib_valloc_free (&smm->va_allocator, fs->ssvm.requested_va);
82
83 if (sm->app_wrk_index != SEGMENT_MANAGER_INVALID_APP_INDEX)
84 {
85 app_worker_t *app_wrk;
86 u64 segment_handle;
87 app_wrk = app_worker_get (sm->app_wrk_index);
88 segment_handle = segment_manager_segment_handle (sm, fs);
89 app_worker_del_segment_notify (app_wrk, segment_handle);
90 }
91 }
Florin Corasa332c462018-01-31 06:52:17 -080092
93 ssvm_delete (&fs->ssvm);
94
95 if (CLIB_DEBUG)
Dave Barachb7b92992018-10-17 10:38:51 -040096 clib_memset (fs, 0xfb, sizeof (*fs));
Florin Corasa332c462018-01-31 06:52:17 -080097 pool_put (sm->segments, fs);
98}
99
100/**
101 * Removes segment after acquiring writer lock
102 */
Florin Coras99368312018-08-02 10:45:44 -0700103static inline void
Florin Corasa332c462018-01-31 06:52:17 -0800104segment_manager_lock_and_del_segment (segment_manager_t * sm, u32 fs_index)
105{
106 svm_fifo_segment_private_t *fs;
107 u8 is_prealloc;
108
109 clib_rwlock_writer_lock (&sm->segments_rwlock);
110 fs = segment_manager_get_segment (sm, fs_index);
111 is_prealloc = svm_fifo_segment_flags (fs) & FIFO_SEGMENT_F_IS_PREALLOCATED;
112 if (is_prealloc && !segment_manager_app_detached (sm))
Florin Coras9d063042017-09-14 03:08:00 -0400113 {
Florin Corasa332c462018-01-31 06:52:17 -0800114 clib_rwlock_writer_unlock (&sm->segments_rwlock);
Florin Coras9d063042017-09-14 03:08:00 -0400115 return;
116 }
Florin Corasa332c462018-01-31 06:52:17 -0800117
118 segment_manager_del_segment (sm, fs);
119 clib_rwlock_writer_unlock (&sm->segments_rwlock);
120}
121
122/**
123 * Reads a segment from the segment manager's pool without lock
124 */
125svm_fifo_segment_private_t *
126segment_manager_get_segment (segment_manager_t * sm, u32 segment_index)
127{
128 return pool_elt_at_index (sm->segments, segment_index);
129}
130
Florin Corasfa76a762018-11-29 12:40:10 -0800131u64
132segment_manager_segment_handle (segment_manager_t * sm,
133 svm_fifo_segment_private_t * segment)
134{
135 u32 segment_index = segment_manager_segment_index (sm, segment);
136 return (((u64) segment_manager_index (sm) << 32) | segment_index);
137}
138
139void
140segment_manager_parse_segment_handle (u64 segment_handle, u32 * sm_index,
141 u32 * segment_index)
142{
143 *sm_index = segment_handle >> 32;
144 *segment_index = segment_handle & 0xFFFFFFFF;
145}
146
147svm_fifo_segment_private_t *
148segment_manager_get_segment_w_handle (u64 segment_handle)
149{
150 u32 sm_index, segment_index;
151 segment_manager_t *sm;
152
153 segment_manager_parse_segment_handle (segment_handle, &sm_index,
154 &segment_index);
155 sm = segment_manager_get (sm_index);
156 if (!sm || pool_is_free_index (sm->segments, segment_index))
157 return 0;
158 return pool_elt_at_index (sm->segments, segment_index);
159}
160
Florin Corasa332c462018-01-31 06:52:17 -0800161/**
162 * Reads a segment from the segment manager's pool and acquires reader lock
163 *
164 * Caller must drop the reader's lock by calling
165 * @ref segment_manager_segment_reader_unlock once it finishes working with
166 * the segment.
167 */
168svm_fifo_segment_private_t *
169segment_manager_get_segment_w_lock (segment_manager_t * sm, u32 segment_index)
170{
171 clib_rwlock_reader_lock (&sm->segments_rwlock);
172 return pool_elt_at_index (sm->segments, segment_index);
173}
174
175void
176segment_manager_segment_reader_unlock (segment_manager_t * sm)
177{
Florin Corasf8f516a2018-02-08 15:10:09 -0800178 ASSERT (sm->segments_rwlock->n_readers > 0);
Florin Corasa332c462018-01-31 06:52:17 -0800179 clib_rwlock_reader_unlock (&sm->segments_rwlock);
180}
181
182void
183segment_manager_segment_writer_unlock (segment_manager_t * sm)
184{
185 clib_rwlock_writer_unlock (&sm->segments_rwlock);
186}
187
188/**
189 * Adds segment to segment manager's pool
190 *
191 * If needed a writer's lock is acquired before allocating a new segment
192 * to avoid affecting any of the segments pool readers.
193 */
Florin Corasf8f516a2018-02-08 15:10:09 -0800194int
Florin Corasa332c462018-01-31 06:52:17 -0800195segment_manager_add_segment (segment_manager_t * sm, u32 segment_size)
196{
197 segment_manager_main_t *smm = &segment_manager_main;
Florin Coras5da96a72018-07-12 01:45:13 -0700198 u32 rnd_margin = 128 << 10, seg_index, page_size;
Florin Corasa332c462018-01-31 06:52:17 -0800199 segment_manager_properties_t *props;
David Johnsond9818dd2018-12-14 14:53:41 -0500200 uword baseva = (uword) ~ 0ULL, alloc_size;
Florin Corasa332c462018-01-31 06:52:17 -0800201 svm_fifo_segment_private_t *seg;
202 u8 *seg_name;
203 int rv;
204
205 props = segment_manager_properties_get (sm);
206
207 /* Not configured for addition of new segments and not first */
208 if (!props->add_segment && !segment_size)
209 {
210 clib_warning ("cannot allocate new segment");
211 return VNET_API_ERROR_INVALID_VALUE;
212 }
213
214 /*
215 * Allocate fifo segment and lock if needed
216 */
217 if (vlib_num_workers ())
218 {
219 clib_rwlock_writer_lock (&sm->segments_rwlock);
220 pool_get (sm->segments, seg);
221 }
222 else
223 {
224 pool_get (sm->segments, seg);
225 }
Dave Barachb7b92992018-10-17 10:38:51 -0400226 clib_memset (seg, 0, sizeof (*seg));
Florin Corasa332c462018-01-31 06:52:17 -0800227
228 /*
229 * Initialize ssvm segment and svm fifo private header
230 */
231 segment_size = segment_size ? segment_size : props->add_segment_size;
Florin Coras5da96a72018-07-12 01:45:13 -0700232 page_size = clib_mem_get_page_size ();
233 segment_size = (segment_size + page_size - 1) & ~(page_size - 1);
Florin Corasa332c462018-01-31 06:52:17 -0800234 if (props->segment_type != SSVM_SEGMENT_PRIVATE)
235 {
236 seg_name = format (0, "%d-%d%c", getpid (), segment_name_counter++, 0);
Florin Coras86f04502018-09-12 16:08:01 -0700237 alloc_size = (uword) segment_size + rnd_margin;
Florin Corasa332c462018-01-31 06:52:17 -0800238 baseva = clib_valloc_alloc (&smm->va_allocator, alloc_size, 0);
239 if (!baseva)
240 {
241 clib_warning ("out of space for segments");
242 return -1;
243 }
244 }
245 else
246 seg_name = format (0, "%s%c", "process-private-segment", 0);
247
248 seg->ssvm.ssvm_size = segment_size;
249 seg->ssvm.name = seg_name;
250 seg->ssvm.requested_va = baseva;
251
252 if ((rv = ssvm_master_init (&seg->ssvm, props->segment_type)))
253 {
254 clib_warning ("svm_master_init ('%v', %u) failed", seg_name,
255 segment_size);
256
257 if (props->segment_type != SSVM_SEGMENT_PRIVATE)
258 clib_valloc_free (&smm->va_allocator, baseva);
259 pool_put (sm->segments, seg);
260 return (rv);
261 }
262
263 svm_fifo_segment_init (seg);
264
265 /*
266 * Save segment index before dropping lock, if any held
267 */
268 seg_index = seg - sm->segments;
269
270 if (vlib_num_workers ())
271 clib_rwlock_writer_unlock (&sm->segments_rwlock);
272
273 return seg_index;
274}
275
276segment_manager_t *
277segment_manager_new ()
278{
279 segment_manager_main_t *smm = &segment_manager_main;
280 segment_manager_t *sm;
281 pool_get (smm->segment_managers, sm);
Dave Barachb7b92992018-10-17 10:38:51 -0400282 clib_memset (sm, 0, sizeof (*sm));
Florin Corasa332c462018-01-31 06:52:17 -0800283 clib_rwlock_init (&sm->segments_rwlock);
284 return sm;
285}
286
287/**
288 * Initializes segment manager based on options provided.
289 * Returns error if ssvm segment(s) allocation fails.
290 */
291int
292segment_manager_init (segment_manager_t * sm, u32 first_seg_size,
Florin Corasf8f516a2018-02-08 15:10:09 -0800293 u32 prealloc_fifo_pairs)
Florin Corasa332c462018-01-31 06:52:17 -0800294{
295 u32 rx_fifo_size, tx_fifo_size, pair_size;
296 u32 rx_rounded_data_size, tx_rounded_data_size;
Florin Coras86f04502018-09-12 16:08:01 -0700297 u64 approx_total_size, max_seg_size = ((u64) 1 << 32) - (128 << 10);
Florin Corasa332c462018-01-31 06:52:17 -0800298 segment_manager_properties_t *props;
299 svm_fifo_segment_private_t *segment;
300 u32 approx_segment_count;
301 int seg_index, i;
302
303 props = segment_manager_properties_get (sm);
304 first_seg_size = clib_max (first_seg_size, default_segment_size);
305
306 if (prealloc_fifo_pairs)
307 {
308 /* Figure out how many segments should be preallocated */
309 rx_rounded_data_size = (1 << (max_log2 (props->rx_fifo_size)));
310 tx_rounded_data_size = (1 << (max_log2 (props->tx_fifo_size)));
311
312 rx_fifo_size = sizeof (svm_fifo_t) + rx_rounded_data_size;
313 tx_fifo_size = sizeof (svm_fifo_t) + tx_rounded_data_size;
314 pair_size = rx_fifo_size + tx_fifo_size;
315
316 approx_total_size = (u64) prealloc_fifo_pairs *pair_size;
317 if (first_seg_size > approx_total_size)
318 max_seg_size = first_seg_size;
319 approx_segment_count = (approx_total_size + (max_seg_size - 1))
320 / max_seg_size;
321
322 /* Allocate the segments */
323 for (i = 0; i < approx_segment_count + 1; i++)
324 {
325 seg_index = segment_manager_add_segment (sm, max_seg_size);
326 if (seg_index < 0)
327 {
328 clib_warning ("Failed to preallocate segment %d", i);
329 return seg_index;
330 }
331
Florin Corasa332c462018-01-31 06:52:17 -0800332 segment = segment_manager_get_segment (sm, seg_index);
Florin Corasf8f516a2018-02-08 15:10:09 -0800333 if (i == 0)
Florin Coras99368312018-08-02 10:45:44 -0700334 sm->event_queue = segment_manager_alloc_queue (segment, props);
Florin Corasf8f516a2018-02-08 15:10:09 -0800335
Florin Corasa332c462018-01-31 06:52:17 -0800336 svm_fifo_segment_preallocate_fifo_pairs (segment,
337 props->rx_fifo_size,
338 props->tx_fifo_size,
339 &prealloc_fifo_pairs);
340 svm_fifo_segment_flags (segment) = FIFO_SEGMENT_F_IS_PREALLOCATED;
341 if (prealloc_fifo_pairs == 0)
342 break;
343 }
344 }
345 else
346 {
347 seg_index = segment_manager_add_segment (sm, first_seg_size);
348 if (seg_index)
349 {
350 clib_warning ("Failed to allocate segment");
351 return seg_index;
352 }
Florin Corasf8f516a2018-02-08 15:10:09 -0800353 segment = segment_manager_get_segment (sm, seg_index);
Florin Coras99368312018-08-02 10:45:44 -0700354 sm->event_queue = segment_manager_alloc_queue (segment, props);
Florin Corasa332c462018-01-31 06:52:17 -0800355 }
356
357 return 0;
358}
359
360u8
361segment_manager_has_fifos (segment_manager_t * sm)
362{
363 svm_fifo_segment_private_t *seg;
364 u8 first = 1;
365
366 /* *INDENT-OFF* */
367 segment_manager_foreach_segment_w_lock (seg, sm, ({
368 if (CLIB_DEBUG && !first && !svm_fifo_segment_has_fifos (seg)
369 && !(svm_fifo_segment_flags (seg) & FIFO_SEGMENT_F_IS_PREALLOCATED))
370 {
371 clib_warning ("segment %d has no fifos!",
372 segment_manager_segment_index (sm, seg));
373 first = 0;
374 }
375 if (svm_fifo_segment_has_fifos (seg))
376 {
377 segment_manager_segment_reader_unlock (sm);
378 return 1;
379 }
380 }));
381 /* *INDENT-ON* */
382
383 return 0;
Florin Corasc87c91d2017-08-16 19:55:49 -0700384}
385
386/**
387 * Initiate disconnects for all sessions 'owned' by a segment manager
Florin Coras6cf30ad2017-04-04 23:08:23 -0700388 */
389void
Florin Corasc87c91d2017-08-16 19:55:49 -0700390segment_manager_del_sessions (segment_manager_t * sm)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700391{
Dave Wallace7b749fe2017-07-05 14:30:46 -0400392 svm_fifo_segment_private_t *fifo_segment;
Florin Coras2b81e3c2019-02-27 07:55:46 -0800393 session_handle_t *handles = 0, *handle;
Florin Coras288eaab2019-02-03 15:26:14 -0800394 session_t *session;
Florin Corasc87c91d2017-08-16 19:55:49 -0700395 svm_fifo_t *fifo;
396
Florin Corasa332c462018-01-31 06:52:17 -0800397 ASSERT (pool_elts (sm->segments) != 0);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700398
399 /* Across all fifo segments used by the server */
Florin Corasa332c462018-01-31 06:52:17 -0800400 /* *INDENT-OFF* */
401 segment_manager_foreach_segment_w_lock (fifo_segment, sm, ({
402 fifo = svm_fifo_segment_get_fifo_list (fifo_segment);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700403
Florin Corasa332c462018-01-31 06:52:17 -0800404 /*
405 * Remove any residual sessions from the session lookup table
406 * Don't bother deleting the individual fifos, we're going to
407 * throw away the fifo segment in a minute.
408 */
409 while (fifo)
410 {
Florin Coras326b81e2018-10-04 19:03:05 -0700411 if (fifo->ct_session_index != SVM_FIFO_INVALID_SESSION_INDEX)
Florin Coras2b81e3c2019-02-27 07:55:46 -0800412 session = session_get (fifo->ct_session_index, 0);
413 else
414 session = session_get (fifo->master_session_index,
415 fifo->master_thread_index);
416 vec_add1 (handles, session_handle (session));
Florin Corasa332c462018-01-31 06:52:17 -0800417 fifo = fifo->next;
418 }
Florin Coras6cf30ad2017-04-04 23:08:23 -0700419
Florin Corasa332c462018-01-31 06:52:17 -0800420 /* Instead of removing the segment, test when cleaning up disconnected
421 * sessions if the segment can be removed.
422 */
423 }));
424 /* *INDENT-ON* */
Florin Coras2b81e3c2019-02-27 07:55:46 -0800425
426 vec_foreach (handle, handles)
427 session_close (session_get_from_handle (*handle));
Florin Corasc87c91d2017-08-16 19:55:49 -0700428}
Florin Coras6cf30ad2017-04-04 23:08:23 -0700429
Florin Corasc87c91d2017-08-16 19:55:49 -0700430/**
431 * Removes segment manager.
432 *
433 * Since the fifos allocated in the segment keep backpointers to the sessions
434 * prior to removing the segment, we call session disconnect. This
Florin Coras9d063042017-09-14 03:08:00 -0400435 * subsequently propagates into transport.
Florin Corasc87c91d2017-08-16 19:55:49 -0700436 */
437void
438segment_manager_del (segment_manager_t * sm)
439{
Florin Corasa332c462018-01-31 06:52:17 -0800440 segment_manager_main_t *smm = &segment_manager_main;
441 svm_fifo_segment_private_t *fifo_segment;
Dave Wallace7b749fe2017-07-05 14:30:46 -0400442
Florin Coras9d063042017-09-14 03:08:00 -0400443 ASSERT (!segment_manager_has_fifos (sm)
444 && segment_manager_app_detached (sm));
445
446 /* If we have empty preallocated segments that haven't been removed, remove
447 * them now. Apart from that, the first segment in the first segment manager
448 * is not removed when all fifos are removed. It can only be removed when
449 * the manager is explicitly deleted/detached by the app. */
Florin Corasa332c462018-01-31 06:52:17 -0800450 clib_rwlock_writer_lock (&sm->segments_rwlock);
451
452 /* *INDENT-OFF* */
453 pool_foreach (fifo_segment, sm->segments, ({
454 segment_manager_del_segment (sm, fifo_segment);
455 }));
456 /* *INDENT-ON* */
457
458 clib_rwlock_writer_unlock (&sm->segments_rwlock);
459
460 clib_rwlock_free (&sm->segments_rwlock);
Florin Corasc87c91d2017-08-16 19:55:49 -0700461 if (CLIB_DEBUG)
Dave Barachb7b92992018-10-17 10:38:51 -0400462 clib_memset (sm, 0xfe, sizeof (*sm));
Florin Corasa332c462018-01-31 06:52:17 -0800463 pool_put (smm->segment_managers, sm);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700464}
465
Florin Corasc87c91d2017-08-16 19:55:49 -0700466void
467segment_manager_init_del (segment_manager_t * sm)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700468{
Florin Coras4e4531e2017-11-06 23:27:56 -0800469 segment_manager_app_detach (sm);
Florin Corasc87c91d2017-08-16 19:55:49 -0700470 if (segment_manager_has_fifos (sm))
471 segment_manager_del_sessions (sm);
472 else
473 {
Florin Coras9d063042017-09-14 03:08:00 -0400474 ASSERT (!sm->first_is_protected || segment_manager_app_detached (sm));
Florin Corasc87c91d2017-08-16 19:55:49 -0700475 segment_manager_del (sm);
476 }
Florin Coras6cf30ad2017-04-04 23:08:23 -0700477}
478
Florin Corasf8f516a2018-02-08 15:10:09 -0800479int
480segment_manager_try_alloc_fifos (svm_fifo_segment_private_t * fifo_segment,
481 u32 rx_fifo_size, u32 tx_fifo_size,
482 svm_fifo_t ** rx_fifo, svm_fifo_t ** tx_fifo)
Florin Corasa332c462018-01-31 06:52:17 -0800483{
484 rx_fifo_size = clib_max (rx_fifo_size, default_fifo_size);
485 *rx_fifo = svm_fifo_segment_alloc_fifo (fifo_segment, rx_fifo_size,
486 FIFO_SEGMENT_RX_FREELIST);
487
488 tx_fifo_size = clib_max (tx_fifo_size, default_fifo_size);
489 *tx_fifo = svm_fifo_segment_alloc_fifo (fifo_segment, tx_fifo_size,
490 FIFO_SEGMENT_TX_FREELIST);
491
492 if (*rx_fifo == 0)
493 {
494 /* This would be very odd, but handle it... */
495 if (*tx_fifo != 0)
496 {
497 svm_fifo_segment_free_fifo (fifo_segment, *tx_fifo,
498 FIFO_SEGMENT_TX_FREELIST);
499 *tx_fifo = 0;
500 }
501 return -1;
502 }
503 if (*tx_fifo == 0)
504 {
505 if (*rx_fifo != 0)
506 {
507 svm_fifo_segment_free_fifo (fifo_segment, *rx_fifo,
508 FIFO_SEGMENT_RX_FREELIST);
509 *rx_fifo = 0;
510 }
511 return -1;
512 }
513
514 return 0;
515}
516
Florin Coras6cf30ad2017-04-04 23:08:23 -0700517int
518segment_manager_alloc_session_fifos (segment_manager_t * sm,
Florin Corasb384b542018-01-15 01:08:33 -0800519 svm_fifo_t ** rx_fifo,
520 svm_fifo_t ** tx_fifo,
Florin Coras6cf30ad2017-04-04 23:08:23 -0700521 u32 * fifo_segment_index)
522{
Florin Corasf8f516a2018-02-08 15:10:09 -0800523 svm_fifo_segment_private_t *fifo_segment = 0;
Florin Corasa332c462018-01-31 06:52:17 -0800524 int alloc_fail = 1, rv = 0, new_fs_index;
Florin Corasad0c77f2017-11-09 18:00:15 -0800525 segment_manager_properties_t *props;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700526 u8 added_a_segment = 0;
Florin Corasfa76a762018-11-29 12:40:10 -0800527 u64 segment_handle;
Florin Corasa332c462018-01-31 06:52:17 -0800528 u32 sm_index;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700529
Florin Corasa332c462018-01-31 06:52:17 -0800530 props = segment_manager_properties_get (sm);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700531
Florin Corasa332c462018-01-31 06:52:17 -0800532 /*
533 * Find the first free segment to allocate the fifos in
534 */
Florin Corasa5464812017-04-19 13:00:05 -0700535
Florin Corasa332c462018-01-31 06:52:17 -0800536 /* *INDENT-OFF* */
537 segment_manager_foreach_segment_w_lock (fifo_segment, sm, ({
Florin Corasf8f516a2018-02-08 15:10:09 -0800538 alloc_fail = segment_manager_try_alloc_fifos (fifo_segment,
539 props->rx_fifo_size,
540 props->tx_fifo_size,
541 rx_fifo, tx_fifo);
Florin Corasa332c462018-01-31 06:52:17 -0800542 /* Exit with lock held, drop it after notifying app */
543 if (!alloc_fail)
544 goto alloc_success;
545 }));
546 /* *INDENT-ON* */
547
548alloc_check:
549
550 if (!alloc_fail)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700551 {
Florin Coras6cf30ad2017-04-04 23:08:23 -0700552
Florin Corasa332c462018-01-31 06:52:17 -0800553 alloc_success:
Florin Coras6cf30ad2017-04-04 23:08:23 -0700554
Florin Corasa332c462018-01-31 06:52:17 -0800555 ASSERT (rx_fifo && tx_fifo);
556 sm_index = segment_manager_index (sm);
Florin Corasfa76a762018-11-29 12:40:10 -0800557 *fifo_segment_index = segment_manager_segment_index (sm, fifo_segment);
Florin Corasa332c462018-01-31 06:52:17 -0800558 (*tx_fifo)->segment_manager = sm_index;
559 (*rx_fifo)->segment_manager = sm_index;
Florin Corasfa76a762018-11-29 12:40:10 -0800560 (*tx_fifo)->segment_index = *fifo_segment_index;
561 (*rx_fifo)->segment_index = *fifo_segment_index;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700562
Florin Corasa332c462018-01-31 06:52:17 -0800563 if (added_a_segment)
Florin Corasfa76a762018-11-29 12:40:10 -0800564 {
Florin Coras2b81e3c2019-02-27 07:55:46 -0800565 app_worker_t *app_wrk;
Florin Corasfa76a762018-11-29 12:40:10 -0800566 segment_handle = segment_manager_segment_handle (sm, fifo_segment);
Florin Coras2b81e3c2019-02-27 07:55:46 -0800567 app_wrk = app_worker_get (sm->app_wrk_index);
568 rv = app_worker_add_segment_notify (app_wrk, segment_handle);
Florin Corasfa76a762018-11-29 12:40:10 -0800569 }
Florin Corasa332c462018-01-31 06:52:17 -0800570 /* Drop the lock after app is notified */
571 segment_manager_segment_reader_unlock (sm);
572 return rv;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700573 }
574
Florin Corasa332c462018-01-31 06:52:17 -0800575 /*
576 * Allocation failed, see if we can add a new segment
577 */
578 if (props->add_segment)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700579 {
Florin Corasa332c462018-01-31 06:52:17 -0800580 if (added_a_segment)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700581 {
Florin Corasa332c462018-01-31 06:52:17 -0800582 clib_warning ("Added a segment, still can't allocate a fifo");
583 segment_manager_segment_reader_unlock (sm);
584 return SESSION_ERROR_NEW_SEG_NO_SPACE;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700585 }
Florin Corasa332c462018-01-31 06:52:17 -0800586 if ((new_fs_index = segment_manager_add_segment (sm, 0)) < 0)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700587 {
Florin Corasa332c462018-01-31 06:52:17 -0800588 clib_warning ("Failed to add new segment");
589 return SESSION_ERROR_SEG_CREATE;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700590 }
Florin Corasa332c462018-01-31 06:52:17 -0800591 fifo_segment = segment_manager_get_segment_w_lock (sm, new_fs_index);
Florin Corasf8f516a2018-02-08 15:10:09 -0800592 alloc_fail = segment_manager_try_alloc_fifos (fifo_segment,
593 props->rx_fifo_size,
594 props->tx_fifo_size,
595 rx_fifo, tx_fifo);
Florin Corasa332c462018-01-31 06:52:17 -0800596 added_a_segment = 1;
597 goto alloc_check;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700598 }
Florin Corasa332c462018-01-31 06:52:17 -0800599 else
600 {
601 clib_warning ("Can't add new seg and no space to allocate fifos!");
602 return SESSION_ERROR_NO_SPACE;
603 }
Florin Coras6cf30ad2017-04-04 23:08:23 -0700604}
605
606void
Florin Coras19223e02019-03-03 14:56:05 -0800607segment_manager_dealloc_fifos (svm_fifo_t * rx_fifo, svm_fifo_t * tx_fifo)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700608{
Florin Coras6cf30ad2017-04-04 23:08:23 -0700609 svm_fifo_segment_private_t *fifo_segment;
Florin Corasa332c462018-01-31 06:52:17 -0800610 segment_manager_t *sm;
Florin Coras19223e02019-03-03 14:56:05 -0800611 u32 segment_index;
Florin Corasa5464812017-04-19 13:00:05 -0700612
Florin Coras58a93e82019-01-14 23:33:46 -0800613 if (!rx_fifo || !tx_fifo)
614 return;
615
Florin Corasa5464812017-04-19 13:00:05 -0700616 /* It's possible to have no segment manager if the session was removed
Florin Corasc87c91d2017-08-16 19:55:49 -0700617 * as result of a detach. */
Florin Corasa332c462018-01-31 06:52:17 -0800618 if (!(sm = segment_manager_get_if_valid (rx_fifo->segment_manager)))
Florin Corasa5464812017-04-19 13:00:05 -0700619 return;
620
Florin Coras19223e02019-03-03 14:56:05 -0800621 segment_index = rx_fifo->segment_index;
Florin Corasa332c462018-01-31 06:52:17 -0800622 fifo_segment = segment_manager_get_segment_w_lock (sm, segment_index);
Dave Barach10d8cc62017-05-30 09:30:07 -0400623 svm_fifo_segment_free_fifo (fifo_segment, rx_fifo,
624 FIFO_SEGMENT_RX_FREELIST);
625 svm_fifo_segment_free_fifo (fifo_segment, tx_fifo,
626 FIFO_SEGMENT_TX_FREELIST);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700627
Florin Corasc87c91d2017-08-16 19:55:49 -0700628 /*
629 * Try to remove svm segment if it has no fifos. This can be done only if
630 * the segment is not the first in the segment manager or if it is first
631 * and it is not protected. Moreover, if the segment is first and the app
632 * has detached from the segment manager, remove the segment manager.
633 */
634 if (!svm_fifo_segment_has_fifos (fifo_segment))
Florin Coras6cf30ad2017-04-04 23:08:23 -0700635 {
Florin Corasa332c462018-01-31 06:52:17 -0800636 segment_manager_segment_reader_unlock (sm);
Florin Corasc87c91d2017-08-16 19:55:49 -0700637
638 /* Remove segment if it holds no fifos or first but not protected */
Florin Corasa332c462018-01-31 06:52:17 -0800639 if (segment_index != 0 || !sm->first_is_protected)
640 segment_manager_lock_and_del_segment (sm, segment_index);
Florin Corasc87c91d2017-08-16 19:55:49 -0700641
642 /* Remove segment manager if no sessions and detached from app */
Florin Coras9d063042017-09-14 03:08:00 -0400643 if (segment_manager_app_detached (sm)
644 && !segment_manager_has_fifos (sm))
Florin Coras568ebc72018-09-18 16:12:50 -0700645 {
646 segment_manager_del (sm);
647 }
Florin Coras6cf30ad2017-04-04 23:08:23 -0700648 }
Florin Corasa332c462018-01-31 06:52:17 -0800649 else
650 segment_manager_segment_reader_unlock (sm);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700651}
652
Florin Coras3c2fed52018-07-04 04:15:05 -0700653u32
654segment_manager_evt_q_expected_size (u32 q_len)
655{
656 u32 fifo_evt_size, notif_q_size, q_hdrs;
657 u32 msg_q_sz, fifo_evt_ring_sz, session_ntf_ring_sz;
658
Florin Coras52207f12018-07-12 14:48:06 -0700659 fifo_evt_size = 1 << max_log2 (sizeof (session_event_t));
Florin Coras3c2fed52018-07-04 04:15:05 -0700660 notif_q_size = clib_max (16, q_len >> 4);
661
662 msg_q_sz = q_len * sizeof (svm_msg_q_msg_t);
663 fifo_evt_ring_sz = q_len * fifo_evt_size;
664 session_ntf_ring_sz = notif_q_size * 256;
665 q_hdrs = sizeof (svm_queue_t) + sizeof (svm_msg_q_t);
666
667 return (msg_q_sz + fifo_evt_ring_sz + session_ntf_ring_sz + q_hdrs);
668}
669
Florin Corasa5464812017-04-19 13:00:05 -0700670/**
671 * Allocates shm queue in the first segment
Florin Corasa332c462018-01-31 06:52:17 -0800672 *
673 * Must be called with lock held
Florin Corasa5464812017-04-19 13:00:05 -0700674 */
Florin Coras3c2fed52018-07-04 04:15:05 -0700675svm_msg_q_t *
Florin Corasf8f516a2018-02-08 15:10:09 -0800676segment_manager_alloc_queue (svm_fifo_segment_private_t * segment,
Florin Coras99368312018-08-02 10:45:44 -0700677 segment_manager_properties_t * props)
Florin Corasa5464812017-04-19 13:00:05 -0700678{
Florin Coras3c2fed52018-07-04 04:15:05 -0700679 u32 fifo_evt_size, session_evt_size = 256, notif_q_size;
680 svm_msg_q_cfg_t _cfg, *cfg = &_cfg;
681 svm_msg_q_t *q;
Florin Corasa5464812017-04-19 13:00:05 -0700682 void *oldheap;
683
Florin Coras52207f12018-07-12 14:48:06 -0700684 fifo_evt_size = sizeof (session_event_t);
Florin Coras99368312018-08-02 10:45:44 -0700685 notif_q_size = clib_max (16, props->evt_q_size >> 4);
Florin Coras3c2fed52018-07-04 04:15:05 -0700686 /* *INDENT-OFF* */
687 svm_msg_q_ring_cfg_t rc[SESSION_MQ_N_RINGS] = {
Florin Coras99368312018-08-02 10:45:44 -0700688 {props->evt_q_size, fifo_evt_size, 0},
Florin Coras3c2fed52018-07-04 04:15:05 -0700689 {notif_q_size, session_evt_size, 0}
690 };
691 /* *INDENT-ON* */
692 cfg->consumer_pid = 0;
693 cfg->n_rings = 2;
Florin Coras99368312018-08-02 10:45:44 -0700694 cfg->q_nitems = props->evt_q_size;
Florin Coras3c2fed52018-07-04 04:15:05 -0700695 cfg->ring_cfgs = rc;
Florin Corasa5464812017-04-19 13:00:05 -0700696
Florin Coras3c2fed52018-07-04 04:15:05 -0700697 oldheap = ssvm_push_heap (segment->ssvm.sh);
698 q = svm_msg_q_alloc (cfg);
Florin Corasa5464812017-04-19 13:00:05 -0700699 ssvm_pop_heap (oldheap);
Florin Coras99368312018-08-02 10:45:44 -0700700
701 if (props->use_mq_eventfd)
702 {
703 if (svm_msg_q_alloc_producer_eventfd (q))
704 clib_warning ("failed to alloc eventfd");
705 }
Florin Corasa5464812017-04-19 13:00:05 -0700706 return q;
707}
708
709/**
710 * Frees shm queue allocated in the first segment
711 */
712void
Florin Corase86a8ed2018-01-05 03:20:25 -0800713segment_manager_dealloc_queue (segment_manager_t * sm, svm_queue_t * q)
Florin Corasa5464812017-04-19 13:00:05 -0700714{
Florin Corasa5464812017-04-19 13:00:05 -0700715 svm_fifo_segment_private_t *segment;
Florin Corasa332c462018-01-31 06:52:17 -0800716 ssvm_shared_header_t *sh;
Florin Corasa5464812017-04-19 13:00:05 -0700717 void *oldheap;
718
Florin Corasa332c462018-01-31 06:52:17 -0800719 ASSERT (!pool_is_free_index (sm->segments, 0));
Florin Corasa5464812017-04-19 13:00:05 -0700720
Florin Corasa332c462018-01-31 06:52:17 -0800721 segment = segment_manager_get_segment_w_lock (sm, 0);
Florin Corasa5464812017-04-19 13:00:05 -0700722 sh = segment->ssvm.sh;
723
724 oldheap = ssvm_push_heap (sh);
Florin Corase86a8ed2018-01-05 03:20:25 -0800725 svm_queue_free (q);
Florin Corasa5464812017-04-19 13:00:05 -0700726 ssvm_pop_heap (oldheap);
Florin Corasa332c462018-01-31 06:52:17 -0800727 segment_manager_segment_reader_unlock (sm);
728}
729
730/*
731 * Init segment vm address allocator
732 */
733void
734segment_manager_main_init (segment_manager_main_init_args_t * a)
735{
736 segment_manager_main_t *sm = &segment_manager_main;
737 clib_valloc_chunk_t _ip, *ip = &_ip;
738
739 ip->baseva = a->baseva;
740 ip->size = a->size;
741
742 clib_valloc_init (&sm->va_allocator, ip, 1 /* lock */ );
Florin Corasa5464812017-04-19 13:00:05 -0700743}
744
Florin Corasc87c91d2017-08-16 19:55:49 -0700745static clib_error_t *
746segment_manager_show_fn (vlib_main_t * vm, unformat_input_t * input,
747 vlib_cli_command_t * cmd)
748{
Florin Corasa332c462018-01-31 06:52:17 -0800749 segment_manager_main_t *smm = &segment_manager_main;
750 svm_fifo_segment_private_t *seg;
Florin Corasc87c91d2017-08-16 19:55:49 -0700751 segment_manager_t *sm;
Florin Corasb384b542018-01-15 01:08:33 -0800752 u8 show_segments = 0, verbose = 0;
David Johnsond9818dd2018-12-14 14:53:41 -0500753 char *address;
754 size_t size;
Dave Barach91f3e742017-09-01 19:12:11 -0400755 u32 active_fifos;
756 u32 free_fifos;
757
Florin Corasc87c91d2017-08-16 19:55:49 -0700758 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
759 {
760 if (unformat (input, "segments"))
761 show_segments = 1;
762 else if (unformat (input, "verbose"))
763 verbose = 1;
764 else
765 return clib_error_return (0, "unknown input `%U'",
766 format_unformat_error, input);
767 }
768 vlib_cli_output (vm, "%d segment managers allocated",
Florin Corasa332c462018-01-31 06:52:17 -0800769 pool_elts (smm->segment_managers));
770 if (verbose && pool_elts (smm->segment_managers))
Florin Corasc87c91d2017-08-16 19:55:49 -0700771 {
772 vlib_cli_output (vm, "%-10s%=15s%=12s", "Index", "App Index",
773 "Segments");
774
775 /* *INDENT-OFF* */
Florin Corasa332c462018-01-31 06:52:17 -0800776 pool_foreach (sm, smm->segment_managers, ({
Florin Coras15531972018-08-12 23:50:53 -0700777 vlib_cli_output (vm, "%-10d%=15d%=12d", segment_manager_index (sm),
778 sm->app_wrk_index, pool_elts (sm->segments));
Florin Corasc87c91d2017-08-16 19:55:49 -0700779 }));
780 /* *INDENT-ON* */
781
782 }
783 if (show_segments)
784 {
Florin Coras2f8d8fa2018-01-26 06:36:04 -0800785 vlib_cli_output (vm, "%-15s%15s%15s%15s%15s%15s", "Name", "Type",
Dave Barach91f3e742017-09-01 19:12:11 -0400786 "HeapSize (M)", "ActiveFifos", "FreeFifos", "Address");
Florin Corasc87c91d2017-08-16 19:55:49 -0700787
788 /* *INDENT-OFF* */
Florin Corasa332c462018-01-31 06:52:17 -0800789 pool_foreach (sm, smm->segment_managers, ({
790 segment_manager_foreach_segment_w_lock (seg, sm, ({
791 svm_fifo_segment_info (seg, &address, &size);
792 active_fifos = svm_fifo_segment_num_fifos (seg);
793 free_fifos = svm_fifo_segment_num_free_fifos (seg, ~0 /* size */);
794 vlib_cli_output (vm, "%-15v%15U%15llu%15u%15u%15llx",
795 ssvm_name (&seg->ssvm), format_svm_fifo_segment_type,
796 seg, size >> 20ULL, active_fifos, free_fifos,
797 address);
798 if (verbose)
799 vlib_cli_output (vm, "%U", format_svm_fifo_segment, seg, verbose);
800 }));
Florin Corasc87c91d2017-08-16 19:55:49 -0700801 }));
802 /* *INDENT-ON* */
803
804 }
805 return 0;
806}
807
Florin Corasad0c77f2017-11-09 18:00:15 -0800808/* *INDENT-OFF* */
Florin Corasc87c91d2017-08-16 19:55:49 -0700809VLIB_CLI_COMMAND (segment_manager_show_command, static) =
810{
811 .path = "show segment-manager",
Dave Barach91f3e742017-09-01 19:12:11 -0400812 .short_help = "show segment-manager [segments][verbose]",
Florin Corasc87c91d2017-08-16 19:55:49 -0700813 .function = segment_manager_show_fn,
814};
815/* *INDENT-ON* */
816
Florin Coras6cf30ad2017-04-04 23:08:23 -0700817/*
818 * fd.io coding-style-patch-verification: ON
819 *
820 * Local Variables:
821 * eval: (c-set-style "gnu")
822 * End:
823 */