blob: 25b641de1674c618c61caeca8073b697f97e2c12 [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 Coras653e43f2019-03-04 10:56:23 -0800411 session = session_get_if_valid (fifo->master_session_index,
412 fifo->master_thread_index);
413 if (session)
414 vec_add1 (handles, session_handle (session));
Florin Corasa332c462018-01-31 06:52:17 -0800415 fifo = fifo->next;
416 }
Florin Coras6cf30ad2017-04-04 23:08:23 -0700417
Florin Corasa332c462018-01-31 06:52:17 -0800418 /* Instead of removing the segment, test when cleaning up disconnected
419 * sessions if the segment can be removed.
420 */
421 }));
422 /* *INDENT-ON* */
Florin Coras2b81e3c2019-02-27 07:55:46 -0800423
424 vec_foreach (handle, handles)
425 session_close (session_get_from_handle (*handle));
Florin Corasc87c91d2017-08-16 19:55:49 -0700426}
Florin Coras6cf30ad2017-04-04 23:08:23 -0700427
Florin Corasc87c91d2017-08-16 19:55:49 -0700428/**
429 * Removes segment manager.
430 *
431 * Since the fifos allocated in the segment keep backpointers to the sessions
432 * prior to removing the segment, we call session disconnect. This
Florin Coras9d063042017-09-14 03:08:00 -0400433 * subsequently propagates into transport.
Florin Corasc87c91d2017-08-16 19:55:49 -0700434 */
435void
436segment_manager_del (segment_manager_t * sm)
437{
Florin Corasa332c462018-01-31 06:52:17 -0800438 segment_manager_main_t *smm = &segment_manager_main;
439 svm_fifo_segment_private_t *fifo_segment;
Dave Wallace7b749fe2017-07-05 14:30:46 -0400440
Florin Coras9d063042017-09-14 03:08:00 -0400441 ASSERT (!segment_manager_has_fifos (sm)
442 && segment_manager_app_detached (sm));
443
444 /* If we have empty preallocated segments that haven't been removed, remove
445 * them now. Apart from that, the first segment in the first segment manager
446 * is not removed when all fifos are removed. It can only be removed when
447 * the manager is explicitly deleted/detached by the app. */
Florin Corasa332c462018-01-31 06:52:17 -0800448 clib_rwlock_writer_lock (&sm->segments_rwlock);
449
450 /* *INDENT-OFF* */
451 pool_foreach (fifo_segment, sm->segments, ({
452 segment_manager_del_segment (sm, fifo_segment);
453 }));
454 /* *INDENT-ON* */
455
456 clib_rwlock_writer_unlock (&sm->segments_rwlock);
457
458 clib_rwlock_free (&sm->segments_rwlock);
Florin Corasc87c91d2017-08-16 19:55:49 -0700459 if (CLIB_DEBUG)
Dave Barachb7b92992018-10-17 10:38:51 -0400460 clib_memset (sm, 0xfe, sizeof (*sm));
Florin Corasa332c462018-01-31 06:52:17 -0800461 pool_put (smm->segment_managers, sm);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700462}
463
Florin Corasc87c91d2017-08-16 19:55:49 -0700464void
465segment_manager_init_del (segment_manager_t * sm)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700466{
Florin Coras4e4531e2017-11-06 23:27:56 -0800467 segment_manager_app_detach (sm);
Florin Corasc87c91d2017-08-16 19:55:49 -0700468 if (segment_manager_has_fifos (sm))
469 segment_manager_del_sessions (sm);
470 else
471 {
Florin Coras9d063042017-09-14 03:08:00 -0400472 ASSERT (!sm->first_is_protected || segment_manager_app_detached (sm));
Florin Corasc87c91d2017-08-16 19:55:49 -0700473 segment_manager_del (sm);
474 }
Florin Coras6cf30ad2017-04-04 23:08:23 -0700475}
476
Florin Corasf8f516a2018-02-08 15:10:09 -0800477int
478segment_manager_try_alloc_fifos (svm_fifo_segment_private_t * fifo_segment,
479 u32 rx_fifo_size, u32 tx_fifo_size,
480 svm_fifo_t ** rx_fifo, svm_fifo_t ** tx_fifo)
Florin Corasa332c462018-01-31 06:52:17 -0800481{
482 rx_fifo_size = clib_max (rx_fifo_size, default_fifo_size);
483 *rx_fifo = svm_fifo_segment_alloc_fifo (fifo_segment, rx_fifo_size,
484 FIFO_SEGMENT_RX_FREELIST);
485
486 tx_fifo_size = clib_max (tx_fifo_size, default_fifo_size);
487 *tx_fifo = svm_fifo_segment_alloc_fifo (fifo_segment, tx_fifo_size,
488 FIFO_SEGMENT_TX_FREELIST);
489
490 if (*rx_fifo == 0)
491 {
492 /* This would be very odd, but handle it... */
493 if (*tx_fifo != 0)
494 {
495 svm_fifo_segment_free_fifo (fifo_segment, *tx_fifo,
496 FIFO_SEGMENT_TX_FREELIST);
497 *tx_fifo = 0;
498 }
499 return -1;
500 }
501 if (*tx_fifo == 0)
502 {
503 if (*rx_fifo != 0)
504 {
505 svm_fifo_segment_free_fifo (fifo_segment, *rx_fifo,
506 FIFO_SEGMENT_RX_FREELIST);
507 *rx_fifo = 0;
508 }
509 return -1;
510 }
511
512 return 0;
513}
514
Florin Coras6cf30ad2017-04-04 23:08:23 -0700515int
516segment_manager_alloc_session_fifos (segment_manager_t * sm,
Florin Corasb384b542018-01-15 01:08:33 -0800517 svm_fifo_t ** rx_fifo,
518 svm_fifo_t ** tx_fifo,
Florin Coras6cf30ad2017-04-04 23:08:23 -0700519 u32 * fifo_segment_index)
520{
Florin Corasf8f516a2018-02-08 15:10:09 -0800521 svm_fifo_segment_private_t *fifo_segment = 0;
Florin Corasa332c462018-01-31 06:52:17 -0800522 int alloc_fail = 1, rv = 0, new_fs_index;
Florin Corasad0c77f2017-11-09 18:00:15 -0800523 segment_manager_properties_t *props;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700524 u8 added_a_segment = 0;
Florin Corasfa76a762018-11-29 12:40:10 -0800525 u64 segment_handle;
Florin Corasa332c462018-01-31 06:52:17 -0800526 u32 sm_index;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700527
Florin Corasa332c462018-01-31 06:52:17 -0800528 props = segment_manager_properties_get (sm);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700529
Florin Corasa332c462018-01-31 06:52:17 -0800530 /*
531 * Find the first free segment to allocate the fifos in
532 */
Florin Corasa5464812017-04-19 13:00:05 -0700533
Florin Corasa332c462018-01-31 06:52:17 -0800534 /* *INDENT-OFF* */
535 segment_manager_foreach_segment_w_lock (fifo_segment, sm, ({
Florin Corasf8f516a2018-02-08 15:10:09 -0800536 alloc_fail = segment_manager_try_alloc_fifos (fifo_segment,
537 props->rx_fifo_size,
538 props->tx_fifo_size,
539 rx_fifo, tx_fifo);
Florin Corasa332c462018-01-31 06:52:17 -0800540 /* Exit with lock held, drop it after notifying app */
541 if (!alloc_fail)
542 goto alloc_success;
543 }));
544 /* *INDENT-ON* */
545
546alloc_check:
547
548 if (!alloc_fail)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700549 {
Florin Coras6cf30ad2017-04-04 23:08:23 -0700550
Florin Corasa332c462018-01-31 06:52:17 -0800551 alloc_success:
Florin Coras6cf30ad2017-04-04 23:08:23 -0700552
Florin Corasa332c462018-01-31 06:52:17 -0800553 ASSERT (rx_fifo && tx_fifo);
554 sm_index = segment_manager_index (sm);
Florin Corasfa76a762018-11-29 12:40:10 -0800555 *fifo_segment_index = segment_manager_segment_index (sm, fifo_segment);
Florin Corasa332c462018-01-31 06:52:17 -0800556 (*tx_fifo)->segment_manager = sm_index;
557 (*rx_fifo)->segment_manager = sm_index;
Florin Corasfa76a762018-11-29 12:40:10 -0800558 (*tx_fifo)->segment_index = *fifo_segment_index;
559 (*rx_fifo)->segment_index = *fifo_segment_index;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700560
Florin Corasa332c462018-01-31 06:52:17 -0800561 if (added_a_segment)
Florin Corasfa76a762018-11-29 12:40:10 -0800562 {
Florin Coras2b81e3c2019-02-27 07:55:46 -0800563 app_worker_t *app_wrk;
Florin Corasfa76a762018-11-29 12:40:10 -0800564 segment_handle = segment_manager_segment_handle (sm, fifo_segment);
Florin Coras2b81e3c2019-02-27 07:55:46 -0800565 app_wrk = app_worker_get (sm->app_wrk_index);
566 rv = app_worker_add_segment_notify (app_wrk, segment_handle);
Florin Corasfa76a762018-11-29 12:40:10 -0800567 }
Florin Corasa332c462018-01-31 06:52:17 -0800568 /* Drop the lock after app is notified */
569 segment_manager_segment_reader_unlock (sm);
570 return rv;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700571 }
572
Florin Corasa332c462018-01-31 06:52:17 -0800573 /*
574 * Allocation failed, see if we can add a new segment
575 */
576 if (props->add_segment)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700577 {
Florin Corasa332c462018-01-31 06:52:17 -0800578 if (added_a_segment)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700579 {
Florin Corasa332c462018-01-31 06:52:17 -0800580 clib_warning ("Added a segment, still can't allocate a fifo");
581 segment_manager_segment_reader_unlock (sm);
582 return SESSION_ERROR_NEW_SEG_NO_SPACE;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700583 }
Florin Corasa332c462018-01-31 06:52:17 -0800584 if ((new_fs_index = segment_manager_add_segment (sm, 0)) < 0)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700585 {
Florin Corasa332c462018-01-31 06:52:17 -0800586 clib_warning ("Failed to add new segment");
587 return SESSION_ERROR_SEG_CREATE;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700588 }
Florin Corasa332c462018-01-31 06:52:17 -0800589 fifo_segment = segment_manager_get_segment_w_lock (sm, new_fs_index);
Florin Corasf8f516a2018-02-08 15:10:09 -0800590 alloc_fail = segment_manager_try_alloc_fifos (fifo_segment,
591 props->rx_fifo_size,
592 props->tx_fifo_size,
593 rx_fifo, tx_fifo);
Florin Corasa332c462018-01-31 06:52:17 -0800594 added_a_segment = 1;
595 goto alloc_check;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700596 }
Florin Corasa332c462018-01-31 06:52:17 -0800597 else
598 {
599 clib_warning ("Can't add new seg and no space to allocate fifos!");
600 return SESSION_ERROR_NO_SPACE;
601 }
Florin Coras6cf30ad2017-04-04 23:08:23 -0700602}
603
604void
Florin Coras19223e02019-03-03 14:56:05 -0800605segment_manager_dealloc_fifos (svm_fifo_t * rx_fifo, svm_fifo_t * tx_fifo)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700606{
Florin Coras6cf30ad2017-04-04 23:08:23 -0700607 svm_fifo_segment_private_t *fifo_segment;
Florin Corasa332c462018-01-31 06:52:17 -0800608 segment_manager_t *sm;
Florin Coras19223e02019-03-03 14:56:05 -0800609 u32 segment_index;
Florin Corasa5464812017-04-19 13:00:05 -0700610
Florin Coras58a93e82019-01-14 23:33:46 -0800611 if (!rx_fifo || !tx_fifo)
612 return;
613
Florin Corasa5464812017-04-19 13:00:05 -0700614 /* It's possible to have no segment manager if the session was removed
Florin Corasc87c91d2017-08-16 19:55:49 -0700615 * as result of a detach. */
Florin Corasa332c462018-01-31 06:52:17 -0800616 if (!(sm = segment_manager_get_if_valid (rx_fifo->segment_manager)))
Florin Corasa5464812017-04-19 13:00:05 -0700617 return;
618
Florin Coras19223e02019-03-03 14:56:05 -0800619 segment_index = rx_fifo->segment_index;
Florin Corasa332c462018-01-31 06:52:17 -0800620 fifo_segment = segment_manager_get_segment_w_lock (sm, segment_index);
Dave Barach10d8cc62017-05-30 09:30:07 -0400621 svm_fifo_segment_free_fifo (fifo_segment, rx_fifo,
622 FIFO_SEGMENT_RX_FREELIST);
623 svm_fifo_segment_free_fifo (fifo_segment, tx_fifo,
624 FIFO_SEGMENT_TX_FREELIST);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700625
Florin Corasc87c91d2017-08-16 19:55:49 -0700626 /*
627 * Try to remove svm segment if it has no fifos. This can be done only if
628 * the segment is not the first in the segment manager or if it is first
629 * and it is not protected. Moreover, if the segment is first and the app
630 * has detached from the segment manager, remove the segment manager.
631 */
632 if (!svm_fifo_segment_has_fifos (fifo_segment))
Florin Coras6cf30ad2017-04-04 23:08:23 -0700633 {
Florin Corasa332c462018-01-31 06:52:17 -0800634 segment_manager_segment_reader_unlock (sm);
Florin Corasc87c91d2017-08-16 19:55:49 -0700635
636 /* Remove segment if it holds no fifos or first but not protected */
Florin Corasa332c462018-01-31 06:52:17 -0800637 if (segment_index != 0 || !sm->first_is_protected)
638 segment_manager_lock_and_del_segment (sm, segment_index);
Florin Corasc87c91d2017-08-16 19:55:49 -0700639
640 /* Remove segment manager if no sessions and detached from app */
Florin Coras9d063042017-09-14 03:08:00 -0400641 if (segment_manager_app_detached (sm)
642 && !segment_manager_has_fifos (sm))
Florin Coras568ebc72018-09-18 16:12:50 -0700643 {
644 segment_manager_del (sm);
645 }
Florin Coras6cf30ad2017-04-04 23:08:23 -0700646 }
Florin Corasa332c462018-01-31 06:52:17 -0800647 else
648 segment_manager_segment_reader_unlock (sm);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700649}
650
Florin Coras3c2fed52018-07-04 04:15:05 -0700651u32
652segment_manager_evt_q_expected_size (u32 q_len)
653{
654 u32 fifo_evt_size, notif_q_size, q_hdrs;
655 u32 msg_q_sz, fifo_evt_ring_sz, session_ntf_ring_sz;
656
Florin Coras52207f12018-07-12 14:48:06 -0700657 fifo_evt_size = 1 << max_log2 (sizeof (session_event_t));
Florin Coras3c2fed52018-07-04 04:15:05 -0700658 notif_q_size = clib_max (16, q_len >> 4);
659
660 msg_q_sz = q_len * sizeof (svm_msg_q_msg_t);
661 fifo_evt_ring_sz = q_len * fifo_evt_size;
662 session_ntf_ring_sz = notif_q_size * 256;
663 q_hdrs = sizeof (svm_queue_t) + sizeof (svm_msg_q_t);
664
665 return (msg_q_sz + fifo_evt_ring_sz + session_ntf_ring_sz + q_hdrs);
666}
667
Florin Corasa5464812017-04-19 13:00:05 -0700668/**
669 * Allocates shm queue in the first segment
Florin Corasa332c462018-01-31 06:52:17 -0800670 *
671 * Must be called with lock held
Florin Corasa5464812017-04-19 13:00:05 -0700672 */
Florin Coras3c2fed52018-07-04 04:15:05 -0700673svm_msg_q_t *
Florin Corasf8f516a2018-02-08 15:10:09 -0800674segment_manager_alloc_queue (svm_fifo_segment_private_t * segment,
Florin Coras99368312018-08-02 10:45:44 -0700675 segment_manager_properties_t * props)
Florin Corasa5464812017-04-19 13:00:05 -0700676{
Florin Coras3c2fed52018-07-04 04:15:05 -0700677 u32 fifo_evt_size, session_evt_size = 256, notif_q_size;
678 svm_msg_q_cfg_t _cfg, *cfg = &_cfg;
679 svm_msg_q_t *q;
Florin Corasa5464812017-04-19 13:00:05 -0700680 void *oldheap;
681
Florin Coras52207f12018-07-12 14:48:06 -0700682 fifo_evt_size = sizeof (session_event_t);
Florin Coras99368312018-08-02 10:45:44 -0700683 notif_q_size = clib_max (16, props->evt_q_size >> 4);
Florin Coras3c2fed52018-07-04 04:15:05 -0700684 /* *INDENT-OFF* */
685 svm_msg_q_ring_cfg_t rc[SESSION_MQ_N_RINGS] = {
Florin Coras99368312018-08-02 10:45:44 -0700686 {props->evt_q_size, fifo_evt_size, 0},
Florin Coras3c2fed52018-07-04 04:15:05 -0700687 {notif_q_size, session_evt_size, 0}
688 };
689 /* *INDENT-ON* */
690 cfg->consumer_pid = 0;
691 cfg->n_rings = 2;
Florin Coras99368312018-08-02 10:45:44 -0700692 cfg->q_nitems = props->evt_q_size;
Florin Coras3c2fed52018-07-04 04:15:05 -0700693 cfg->ring_cfgs = rc;
Florin Corasa5464812017-04-19 13:00:05 -0700694
Florin Coras3c2fed52018-07-04 04:15:05 -0700695 oldheap = ssvm_push_heap (segment->ssvm.sh);
696 q = svm_msg_q_alloc (cfg);
Florin Corasa5464812017-04-19 13:00:05 -0700697 ssvm_pop_heap (oldheap);
Florin Coras99368312018-08-02 10:45:44 -0700698
699 if (props->use_mq_eventfd)
700 {
701 if (svm_msg_q_alloc_producer_eventfd (q))
702 clib_warning ("failed to alloc eventfd");
703 }
Florin Corasa5464812017-04-19 13:00:05 -0700704 return q;
705}
706
707/**
708 * Frees shm queue allocated in the first segment
709 */
710void
Florin Corase86a8ed2018-01-05 03:20:25 -0800711segment_manager_dealloc_queue (segment_manager_t * sm, svm_queue_t * q)
Florin Corasa5464812017-04-19 13:00:05 -0700712{
Florin Corasa5464812017-04-19 13:00:05 -0700713 svm_fifo_segment_private_t *segment;
Florin Corasa332c462018-01-31 06:52:17 -0800714 ssvm_shared_header_t *sh;
Florin Corasa5464812017-04-19 13:00:05 -0700715 void *oldheap;
716
Florin Corasa332c462018-01-31 06:52:17 -0800717 ASSERT (!pool_is_free_index (sm->segments, 0));
Florin Corasa5464812017-04-19 13:00:05 -0700718
Florin Corasa332c462018-01-31 06:52:17 -0800719 segment = segment_manager_get_segment_w_lock (sm, 0);
Florin Corasa5464812017-04-19 13:00:05 -0700720 sh = segment->ssvm.sh;
721
722 oldheap = ssvm_push_heap (sh);
Florin Corase86a8ed2018-01-05 03:20:25 -0800723 svm_queue_free (q);
Florin Corasa5464812017-04-19 13:00:05 -0700724 ssvm_pop_heap (oldheap);
Florin Corasa332c462018-01-31 06:52:17 -0800725 segment_manager_segment_reader_unlock (sm);
726}
727
728/*
729 * Init segment vm address allocator
730 */
731void
732segment_manager_main_init (segment_manager_main_init_args_t * a)
733{
734 segment_manager_main_t *sm = &segment_manager_main;
735 clib_valloc_chunk_t _ip, *ip = &_ip;
736
737 ip->baseva = a->baseva;
738 ip->size = a->size;
739
740 clib_valloc_init (&sm->va_allocator, ip, 1 /* lock */ );
Florin Corasa5464812017-04-19 13:00:05 -0700741}
742
Florin Corasc87c91d2017-08-16 19:55:49 -0700743static clib_error_t *
744segment_manager_show_fn (vlib_main_t * vm, unformat_input_t * input,
745 vlib_cli_command_t * cmd)
746{
Florin Corasa332c462018-01-31 06:52:17 -0800747 segment_manager_main_t *smm = &segment_manager_main;
748 svm_fifo_segment_private_t *seg;
Florin Corasc87c91d2017-08-16 19:55:49 -0700749 segment_manager_t *sm;
Florin Corasb384b542018-01-15 01:08:33 -0800750 u8 show_segments = 0, verbose = 0;
David Johnsond9818dd2018-12-14 14:53:41 -0500751 char *address;
752 size_t size;
Dave Barach91f3e742017-09-01 19:12:11 -0400753 u32 active_fifos;
754 u32 free_fifos;
755
Florin Corasc87c91d2017-08-16 19:55:49 -0700756 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
757 {
758 if (unformat (input, "segments"))
759 show_segments = 1;
760 else if (unformat (input, "verbose"))
761 verbose = 1;
762 else
763 return clib_error_return (0, "unknown input `%U'",
764 format_unformat_error, input);
765 }
766 vlib_cli_output (vm, "%d segment managers allocated",
Florin Corasa332c462018-01-31 06:52:17 -0800767 pool_elts (smm->segment_managers));
768 if (verbose && pool_elts (smm->segment_managers))
Florin Corasc87c91d2017-08-16 19:55:49 -0700769 {
770 vlib_cli_output (vm, "%-10s%=15s%=12s", "Index", "App Index",
771 "Segments");
772
773 /* *INDENT-OFF* */
Florin Corasa332c462018-01-31 06:52:17 -0800774 pool_foreach (sm, smm->segment_managers, ({
Florin Coras15531972018-08-12 23:50:53 -0700775 vlib_cli_output (vm, "%-10d%=15d%=12d", segment_manager_index (sm),
776 sm->app_wrk_index, pool_elts (sm->segments));
Florin Corasc87c91d2017-08-16 19:55:49 -0700777 }));
778 /* *INDENT-ON* */
779
780 }
781 if (show_segments)
782 {
Florin Coras2f8d8fa2018-01-26 06:36:04 -0800783 vlib_cli_output (vm, "%-15s%15s%15s%15s%15s%15s", "Name", "Type",
Dave Barach91f3e742017-09-01 19:12:11 -0400784 "HeapSize (M)", "ActiveFifos", "FreeFifos", "Address");
Florin Corasc87c91d2017-08-16 19:55:49 -0700785
786 /* *INDENT-OFF* */
Florin Corasa332c462018-01-31 06:52:17 -0800787 pool_foreach (sm, smm->segment_managers, ({
788 segment_manager_foreach_segment_w_lock (seg, sm, ({
789 svm_fifo_segment_info (seg, &address, &size);
790 active_fifos = svm_fifo_segment_num_fifos (seg);
791 free_fifos = svm_fifo_segment_num_free_fifos (seg, ~0 /* size */);
792 vlib_cli_output (vm, "%-15v%15U%15llu%15u%15u%15llx",
793 ssvm_name (&seg->ssvm), format_svm_fifo_segment_type,
794 seg, size >> 20ULL, active_fifos, free_fifos,
795 address);
796 if (verbose)
797 vlib_cli_output (vm, "%U", format_svm_fifo_segment, seg, verbose);
798 }));
Florin Corasc87c91d2017-08-16 19:55:49 -0700799 }));
800 /* *INDENT-ON* */
801
802 }
803 return 0;
804}
805
Florin Corasad0c77f2017-11-09 18:00:15 -0800806/* *INDENT-OFF* */
Florin Corasc87c91d2017-08-16 19:55:49 -0700807VLIB_CLI_COMMAND (segment_manager_show_command, static) =
808{
809 .path = "show segment-manager",
Dave Barach91f3e742017-09-01 19:12:11 -0400810 .short_help = "show segment-manager [segments][verbose]",
Florin Corasc87c91d2017-08-16 19:55:49 -0700811 .function = segment_manager_show_fn,
812};
813/* *INDENT-ON* */
814
Florin Coras6cf30ad2017-04-04 23:08:23 -0700815/*
816 * fd.io coding-style-patch-verification: ON
817 *
818 * Local Variables:
819 * eval: (c-set-style "gnu")
820 * End:
821 */