blob: c3a794b7fc43cd3df8e361df297f5c6bb7207031 [file] [log] [blame]
Florin Coras6cf30ad2017-04-04 23:08:23 -07001/*
2 * Copyright (c) 2017 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/segment_manager.h>
17#include <vnet/session/session.h>
18#include <vnet/session/application.h>
19
20/**
21 * Counter used to build segment names
22 */
23u32 segment_name_counter = 0;
24
25/**
26 * Pool of segment managers
27 */
28segment_manager_t *segment_managers = 0;
29
Florin Corasad0c77f2017-11-09 18:00:15 -080030/*
31 * Pool of segment manager properties
32 */
33static segment_manager_properties_t *segment_manager_properties_pool;
34
Florin Coras6cf30ad2017-04-04 23:08:23 -070035/**
Florin Corasa5464812017-04-19 13:00:05 -070036 * Process private segment index
37 */
Dave Barach2c25a622017-06-26 11:35:07 -040038u32 *private_segment_indices;
Florin Corasa5464812017-04-19 13:00:05 -070039
40/**
Florin Coras6cf30ad2017-04-04 23:08:23 -070041 * Default fifo and segment size. TODO config.
42 */
43u32 default_fifo_size = 1 << 16;
44u32 default_segment_size = 1 << 20;
45
Florin Corasad0c77f2017-11-09 18:00:15 -080046segment_manager_properties_t *
47segment_manager_properties_alloc (void)
48{
49 segment_manager_properties_t *props;
50 pool_get (segment_manager_properties_pool, props);
51 memset (props, 0, sizeof (*props));
Florin Corasb384b542018-01-15 01:08:33 -080052 props->add_segment_size = default_segment_size;
53 props->rx_fifo_size = default_fifo_size;
54 props->tx_fifo_size = default_fifo_size;
Florin Corasad0c77f2017-11-09 18:00:15 -080055 return props;
56}
57
58void
59segment_manager_properties_free (segment_manager_properties_t * props)
60{
61 pool_put (segment_manager_properties_pool, props);
62 memset (props, 0xFB, sizeof (*props));
63}
64
65segment_manager_properties_t *
66segment_manager_properties_get (u32 smp_index)
67{
68 if (pool_is_free_index (segment_manager_properties_pool, smp_index))
69 return 0;
70 return pool_elt_at_index (segment_manager_properties_pool, smp_index);
71}
72
73u32
74segment_manager_properties_index (segment_manager_properties_t * p)
75{
76 return p - segment_manager_properties_pool;
77}
78
Florin Corasb384b542018-01-15 01:08:33 -080079svm_fifo_segment_private_t *
80segment_manager_get_segment (u32 segment_index)
81{
82 return svm_fifo_segment_get_segment (segment_index);
83}
84
Florin Coras6cf30ad2017-04-04 23:08:23 -070085void
86segment_manager_get_segment_info (u32 index, u8 ** name, u32 * size)
87{
88 svm_fifo_segment_private_t *s;
Florin Corasc87c91d2017-08-16 19:55:49 -070089 s = svm_fifo_segment_get_segment (index);
Florin Corasb384b542018-01-15 01:08:33 -080090 *name = s->ssvm.name;
Florin Coras6cf30ad2017-04-04 23:08:23 -070091 *size = s->ssvm.ssvm_size;
92}
93
94always_inline int
Florin Corasb384b542018-01-15 01:08:33 -080095segment_manager_add_segment_i (segment_manager_t * sm, u32 segment_size,
96 u32 protected_space)
Florin Coras6cf30ad2017-04-04 23:08:23 -070097{
Florin Corasb384b542018-01-15 01:08:33 -080098 svm_fifo_segment_create_args_t _ca = { 0 }, *ca = &_ca;
Florin Corasad0c77f2017-11-09 18:00:15 -080099 segment_manager_properties_t *props;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700100
Florin Corasad0c77f2017-11-09 18:00:15 -0800101 props = segment_manager_properties_get (sm->properties_index);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700102
Florin Corasb384b542018-01-15 01:08:33 -0800103 /* Not configured for addition of new segments and not first */
104 if (!props->add_segment && !segment_size)
105 {
106 clib_warning ("cannot allocate new segment");
107 return VNET_API_ERROR_INVALID_VALUE;
108 }
109
110 ca->segment_size = segment_size ? segment_size : props->add_segment_size;
111 ca->rx_fifo_size = props->rx_fifo_size;
112 ca->tx_fifo_size = props->tx_fifo_size;
113 ca->preallocated_fifo_pairs = props->preallocated_fifo_pairs;
114 ca->seg_protected_space = protected_space ? protected_space : 0;
115
116 if (props->segment_type != SSVM_N_SEGMENT_TYPES)
117 {
118 ca->segment_name = (char *) format (0, "%d-%d%c", getpid (),
119 segment_name_counter++, 0);
120 ca->segment_type = props->segment_type;
121 if (svm_fifo_segment_create (ca))
Florin Corasc87c91d2017-08-16 19:55:49 -0700122 {
123 clib_warning ("svm_fifo_segment_create ('%s', %d) failed",
124 ca->segment_name, ca->segment_size);
125 return VNET_API_ERROR_SVM_SEGMENT_CREATE_FAIL;
126 }
Florin Corasb384b542018-01-15 01:08:33 -0800127 vec_free (ca->segment_name);
Florin Corasc87c91d2017-08-16 19:55:49 -0700128 }
129 else
130 {
Florin Corasb384b542018-01-15 01:08:33 -0800131 u32 rx_fifo_size, tx_fifo_size;
132 u32 rx_rounded_data_size, tx_rounded_data_size;
Dave Barach91f3e742017-09-01 19:12:11 -0400133 u32 approx_segment_count;
134 u64 approx_total_size;
135
Florin Corasc87c91d2017-08-16 19:55:49 -0700136 ca->segment_name = "process-private-segment";
Florin Corasad0c77f2017-11-09 18:00:15 -0800137 ca->private_segment_count = props->private_segment_count;
Dave Barach91f3e742017-09-01 19:12:11 -0400138
139 /* Calculate space requirements */
140 rx_rounded_data_size = (1 << (max_log2 (ca->rx_fifo_size)));
141 tx_rounded_data_size = (1 << (max_log2 (ca->tx_fifo_size)));
142
143 rx_fifo_size = sizeof (svm_fifo_t) + rx_rounded_data_size;
144 tx_fifo_size = sizeof (svm_fifo_t) + tx_rounded_data_size;
145
146 approx_total_size = (u64) ca->preallocated_fifo_pairs
147 * (rx_fifo_size + tx_fifo_size);
Florin Corasb384b542018-01-15 01:08:33 -0800148 approx_segment_count = (approx_total_size + protected_space
149 + (ca->segment_size -
150 1)) / (u64) ca->segment_size;
Dave Barach91f3e742017-09-01 19:12:11 -0400151
152 /* The user asked us to figure it out... */
Florin Corasb384b542018-01-15 01:08:33 -0800153 if (ca->private_segment_count == 0
154 || approx_segment_count < ca->private_segment_count)
Dave Barach91f3e742017-09-01 19:12:11 -0400155 {
156 ca->private_segment_count = approx_segment_count;
157 }
158 /* Follow directions, but issue a warning */
Florin Corasb384b542018-01-15 01:08:33 -0800159 else if (approx_segment_count < ca->private_segment_count)
Dave Barach91f3e742017-09-01 19:12:11 -0400160 {
Florin Corasff6e7692017-12-11 04:59:01 -0800161 clib_warning ("Honoring segment count %u, calculated count was %u",
162 ca->private_segment_count, approx_segment_count);
Dave Barach91f3e742017-09-01 19:12:11 -0400163 }
Florin Corasb384b542018-01-15 01:08:33 -0800164 else if (approx_segment_count > ca->private_segment_count)
165 {
166 clib_warning ("Segment count too low %u, calculated %u.",
167 ca->private_segment_count, approx_segment_count);
168 return VNET_API_ERROR_INVALID_VALUE;
169 }
Dave Barach91f3e742017-09-01 19:12:11 -0400170
Florin Corasc87c91d2017-08-16 19:55:49 -0700171 if (svm_fifo_segment_create_process_private (ca))
172 clib_warning ("Failed to create process private segment");
173
174 ASSERT (vec_len (ca->new_segment_indices));
175 }
Florin Corasb384b542018-01-15 01:08:33 -0800176
Dave Barach2c25a622017-06-26 11:35:07 -0400177 vec_append (sm->segment_indices, ca->new_segment_indices);
178 vec_free (ca->new_segment_indices);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700179 return 0;
180}
181
182int
Florin Corasb384b542018-01-15 01:08:33 -0800183segment_manager_add_segment (segment_manager_t * sm)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700184{
Florin Corasb384b542018-01-15 01:08:33 -0800185 return segment_manager_add_segment_i (sm, 0, 0);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700186}
187
Florin Corasc87c91d2017-08-16 19:55:49 -0700188segment_manager_t *
189segment_manager_new ()
Florin Corasa5464812017-04-19 13:00:05 -0700190{
Florin Corasc87c91d2017-08-16 19:55:49 -0700191 segment_manager_t *sm;
192 pool_get (segment_managers, sm);
193 memset (sm, 0, sizeof (*sm));
194 return sm;
Florin Corasa5464812017-04-19 13:00:05 -0700195}
196
Florin Coras6cf30ad2017-04-04 23:08:23 -0700197/**
198 * Initializes segment manager based on options provided.
199 * Returns error if svm segment allocation fails.
200 */
201int
Florin Corasad0c77f2017-11-09 18:00:15 -0800202segment_manager_init (segment_manager_t * sm, u32 props_index,
Florin Corasb384b542018-01-15 01:08:33 -0800203 u32 first_seg_size, u32 evt_q_size)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700204{
Florin Corasb384b542018-01-15 01:08:33 -0800205 u32 protected_space;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700206 int rv;
207
Florin Corasad0c77f2017-11-09 18:00:15 -0800208 sm->properties_index = props_index;
Florin Corasb384b542018-01-15 01:08:33 -0800209
210 protected_space = max_pow2 (sizeof (svm_queue_t)
211 + evt_q_size * sizeof (session_fifo_event_t));
212 protected_space = round_pow2_u64 (protected_space, CLIB_CACHE_LINE_BYTES);
Florin Corasa5464812017-04-19 13:00:05 -0700213 first_seg_size = first_seg_size > 0 ? first_seg_size : default_segment_size;
Florin Corasb384b542018-01-15 01:08:33 -0800214 rv = segment_manager_add_segment_i (sm, first_seg_size, protected_space);
Florin Corasc87c91d2017-08-16 19:55:49 -0700215 if (rv)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700216 {
Florin Corasc87c91d2017-08-16 19:55:49 -0700217 clib_warning ("Failed to allocate segment");
218 return rv;
Florin Corasa5464812017-04-19 13:00:05 -0700219 }
Florin Coras6cf30ad2017-04-04 23:08:23 -0700220
Florin Corasa5464812017-04-19 13:00:05 -0700221 clib_spinlock_init (&sm->lockp);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700222 return 0;
223}
224
Florin Corasc87c91d2017-08-16 19:55:49 -0700225u8
226segment_manager_has_fifos (segment_manager_t * sm)
Dave Wallace7b749fe2017-07-05 14:30:46 -0400227{
Florin Corasc87c91d2017-08-16 19:55:49 -0700228 svm_fifo_segment_private_t *segment;
Florin Coras9d063042017-09-14 03:08:00 -0400229 int i;
230
231 for (i = 0; i < vec_len (sm->segment_indices); i++)
Dave Wallace7b749fe2017-07-05 14:30:46 -0400232 {
Florin Coras9d063042017-09-14 03:08:00 -0400233 segment = svm_fifo_segment_get_segment (sm->segment_indices[i]);
234 if (CLIB_DEBUG && i && !svm_fifo_segment_has_fifos (segment)
235 && !(segment->h->flags & FIFO_SEGMENT_F_IS_PREALLOCATED))
236 clib_warning ("segment %d has no fifos!", sm->segment_indices[i]);
237 if (svm_fifo_segment_has_fifos (segment))
238 return 1;
Dave Wallace7b749fe2017-07-05 14:30:46 -0400239 }
Florin Coras9d063042017-09-14 03:08:00 -0400240 return 0;
241}
242
243static u8
244segment_manager_app_detached (segment_manager_t * sm)
245{
246 return (sm->app_index == SEGMENT_MANAGER_INVALID_APP_INDEX);
Dave Wallace7b749fe2017-07-05 14:30:46 -0400247}
248
Florin Coras4e4531e2017-11-06 23:27:56 -0800249void
250segment_manager_app_detach (segment_manager_t * sm)
251{
252 sm->app_index = SEGMENT_MANAGER_INVALID_APP_INDEX;
253}
254
Florin Corasc87c91d2017-08-16 19:55:49 -0700255static void
256segment_manager_del_segment (segment_manager_t * sm, u32 segment_index)
257{
258 svm_fifo_segment_private_t *fifo_segment;
259 u32 svm_segment_index;
260 clib_spinlock_lock (&sm->lockp);
Florin Corasb384b542018-01-15 01:08:33 -0800261 svm_segment_index = vec_elt (sm->segment_indices, segment_index);
Florin Corasc87c91d2017-08-16 19:55:49 -0700262 fifo_segment = svm_fifo_segment_get_segment (svm_segment_index);
Florin Coras9d063042017-09-14 03:08:00 -0400263 if (!fifo_segment
264 || ((fifo_segment->h->flags & FIFO_SEGMENT_F_IS_PREALLOCATED)
265 && !segment_manager_app_detached (sm)))
266 {
267 clib_spinlock_unlock (&sm->lockp);
268 return;
269 }
Florin Corasc87c91d2017-08-16 19:55:49 -0700270 svm_fifo_segment_delete (fifo_segment);
271 vec_del1 (sm->segment_indices, segment_index);
272 clib_spinlock_unlock (&sm->lockp);
273}
274
275/**
276 * Initiate disconnects for all sessions 'owned' by a segment manager
Florin Coras6cf30ad2017-04-04 23:08:23 -0700277 */
278void
Florin Corasc87c91d2017-08-16 19:55:49 -0700279segment_manager_del_sessions (segment_manager_t * sm)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700280{
Dave Barach10d8cc62017-05-30 09:30:07 -0400281 int j;
Dave Wallace7b749fe2017-07-05 14:30:46 -0400282 svm_fifo_segment_private_t *fifo_segment;
Florin Corasc87c91d2017-08-16 19:55:49 -0700283 svm_fifo_t *fifo;
284
Dave Wallace7b749fe2017-07-05 14:30:46 -0400285 ASSERT (vec_len (sm->segment_indices));
Florin Coras6cf30ad2017-04-04 23:08:23 -0700286
287 /* Across all fifo segments used by the server */
288 for (j = 0; j < vec_len (sm->segment_indices); j++)
289 {
Florin Corasc87c91d2017-08-16 19:55:49 -0700290 fifo_segment = svm_fifo_segment_get_segment (sm->segment_indices[j]);
Dave Barach10d8cc62017-05-30 09:30:07 -0400291 fifo = svm_fifo_segment_get_fifo_list (fifo_segment);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700292
293 /*
294 * Remove any residual sessions from the session lookup table
295 * Don't bother deleting the individual fifos, we're going to
296 * throw away the fifo segment in a minute.
297 */
Dave Barach10d8cc62017-05-30 09:30:07 -0400298 while (fifo)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700299 {
Florin Coras6cf30ad2017-04-04 23:08:23 -0700300 u32 session_index, thread_index;
301 stream_session_t *session;
302
Florin Corasa5464812017-04-19 13:00:05 -0700303 session_index = fifo->master_session_index;
304 thread_index = fifo->master_thread_index;
Florin Corascea194d2017-10-02 00:18:51 -0700305 session = session_get (session_index, thread_index);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700306
Florin Coras6cf30ad2017-04-04 23:08:23 -0700307 /* Instead of directly removing the session call disconnect */
Florin Corasc87c91d2017-08-16 19:55:49 -0700308 if (session->session_state != SESSION_STATE_CLOSED)
309 {
310 session->session_state = SESSION_STATE_CLOSED;
Florin Corasb384b542018-01-15 01:08:33 -0800311 session_send_session_evt_to_thread (session_handle (session),
Florin Corasc87c91d2017-08-16 19:55:49 -0700312 FIFO_EVENT_DISCONNECT,
313 thread_index);
314 }
Dave Barach10d8cc62017-05-30 09:30:07 -0400315 fifo = fifo->next;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700316 }
317
Dave Barach10d8cc62017-05-30 09:30:07 -0400318 /* Instead of removing the segment, test when cleaning up disconnected
319 * sessions if the segment can be removed.
Florin Coras6cf30ad2017-04-04 23:08:23 -0700320 */
Florin Coras6cf30ad2017-04-04 23:08:23 -0700321 }
Florin Corasc87c91d2017-08-16 19:55:49 -0700322}
Florin Coras6cf30ad2017-04-04 23:08:23 -0700323
Florin Corasc87c91d2017-08-16 19:55:49 -0700324/**
325 * Removes segment manager.
326 *
327 * Since the fifos allocated in the segment keep backpointers to the sessions
328 * prior to removing the segment, we call session disconnect. This
Florin Coras9d063042017-09-14 03:08:00 -0400329 * subsequently propagates into transport.
Florin Corasc87c91d2017-08-16 19:55:49 -0700330 */
331void
332segment_manager_del (segment_manager_t * sm)
333{
Florin Coras9d063042017-09-14 03:08:00 -0400334 int i;
Dave Wallace7b749fe2017-07-05 14:30:46 -0400335
Florin Coras9d063042017-09-14 03:08:00 -0400336 ASSERT (!segment_manager_has_fifos (sm)
337 && segment_manager_app_detached (sm));
338
339 /* If we have empty preallocated segments that haven't been removed, remove
340 * them now. Apart from that, the first segment in the first segment manager
341 * is not removed when all fifos are removed. It can only be removed when
342 * the manager is explicitly deleted/detached by the app. */
343 for (i = vec_len (sm->segment_indices) - 1; i >= 0; i--)
Florin Corasc87c91d2017-08-16 19:55:49 -0700344 {
Florin Corasc87c91d2017-08-16 19:55:49 -0700345 if (CLIB_DEBUG)
346 {
Florin Coras9d063042017-09-14 03:08:00 -0400347 svm_fifo_segment_private_t *segment;
348 segment = svm_fifo_segment_get_segment (sm->segment_indices[i]);
349 ASSERT (!svm_fifo_segment_has_fifos (segment));
Florin Corasc87c91d2017-08-16 19:55:49 -0700350 }
Florin Coras9d063042017-09-14 03:08:00 -0400351 segment_manager_del_segment (sm, i);
Florin Corasc87c91d2017-08-16 19:55:49 -0700352 }
Florin Corasa5464812017-04-19 13:00:05 -0700353 clib_spinlock_free (&sm->lockp);
Florin Corasc87c91d2017-08-16 19:55:49 -0700354 if (CLIB_DEBUG)
355 memset (sm, 0xfe, sizeof (*sm));
Florin Coras6cf30ad2017-04-04 23:08:23 -0700356 pool_put (segment_managers, sm);
357}
358
Florin Corasc87c91d2017-08-16 19:55:49 -0700359void
360segment_manager_init_del (segment_manager_t * sm)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700361{
Florin Coras4e4531e2017-11-06 23:27:56 -0800362 segment_manager_app_detach (sm);
Florin Corasc87c91d2017-08-16 19:55:49 -0700363 if (segment_manager_has_fifos (sm))
364 segment_manager_del_sessions (sm);
365 else
366 {
Florin Coras9d063042017-09-14 03:08:00 -0400367 ASSERT (!sm->first_is_protected || segment_manager_app_detached (sm));
Florin Corasc87c91d2017-08-16 19:55:49 -0700368 segment_manager_del (sm);
369 }
Florin Coras6cf30ad2017-04-04 23:08:23 -0700370}
371
372int
373segment_manager_alloc_session_fifos (segment_manager_t * sm,
Florin Corasb384b542018-01-15 01:08:33 -0800374 svm_fifo_t ** rx_fifo,
375 svm_fifo_t ** tx_fifo,
Florin Coras6cf30ad2017-04-04 23:08:23 -0700376 u32 * fifo_segment_index)
377{
378 svm_fifo_segment_private_t *fifo_segment;
Florin Corasad0c77f2017-11-09 18:00:15 -0800379 segment_manager_properties_t *props;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700380 u32 fifo_size, sm_index;
381 u8 added_a_segment = 0;
382 int i;
383
Florin Coras6cf30ad2017-04-04 23:08:23 -0700384 ASSERT (vec_len (sm->segment_indices));
385
Florin Corasa5464812017-04-19 13:00:05 -0700386 /* Make sure we don't have multiple threads trying to allocate segments
387 * at the same time. */
388 clib_spinlock_lock (&sm->lockp);
389
390 /* Allocate svm fifos */
Florin Corasad0c77f2017-11-09 18:00:15 -0800391 props = segment_manager_properties_get (sm->properties_index);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700392again:
393 for (i = 0; i < vec_len (sm->segment_indices); i++)
394 {
Florin Corasb384b542018-01-15 01:08:33 -0800395 *fifo_segment_index = vec_elt (sm->segment_indices, i);
Florin Corasc87c91d2017-08-16 19:55:49 -0700396 fifo_segment = svm_fifo_segment_get_segment (*fifo_segment_index);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700397
Florin Corasad0c77f2017-11-09 18:00:15 -0800398 fifo_size = props->rx_fifo_size;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700399 fifo_size = (fifo_size == 0) ? default_fifo_size : fifo_size;
Florin Corasb384b542018-01-15 01:08:33 -0800400 *rx_fifo = svm_fifo_segment_alloc_fifo (fifo_segment, fifo_size,
401 FIFO_SEGMENT_RX_FREELIST);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700402
Florin Corasad0c77f2017-11-09 18:00:15 -0800403 fifo_size = props->tx_fifo_size;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700404 fifo_size = (fifo_size == 0) ? default_fifo_size : fifo_size;
Florin Corasb384b542018-01-15 01:08:33 -0800405 *tx_fifo = svm_fifo_segment_alloc_fifo (fifo_segment, fifo_size,
406 FIFO_SEGMENT_TX_FREELIST);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700407
Florin Corasb384b542018-01-15 01:08:33 -0800408 if (*rx_fifo == 0)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700409 {
410 /* This would be very odd, but handle it... */
Florin Corasb384b542018-01-15 01:08:33 -0800411 if (*tx_fifo != 0)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700412 {
Florin Corasb384b542018-01-15 01:08:33 -0800413 svm_fifo_segment_free_fifo (fifo_segment, *tx_fifo,
Dave Barach10d8cc62017-05-30 09:30:07 -0400414 FIFO_SEGMENT_TX_FREELIST);
Florin Corasb384b542018-01-15 01:08:33 -0800415 *tx_fifo = 0;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700416 }
417 continue;
418 }
Florin Corasb384b542018-01-15 01:08:33 -0800419 if (*tx_fifo == 0)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700420 {
Florin Corasb384b542018-01-15 01:08:33 -0800421 if (*rx_fifo != 0)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700422 {
Florin Corasb384b542018-01-15 01:08:33 -0800423 svm_fifo_segment_free_fifo (fifo_segment, *rx_fifo,
Dave Barach10d8cc62017-05-30 09:30:07 -0400424 FIFO_SEGMENT_RX_FREELIST);
Florin Corasb384b542018-01-15 01:08:33 -0800425 *rx_fifo = 0;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700426 }
427 continue;
428 }
429 break;
430 }
431
432 /* See if we're supposed to create another segment */
Florin Corasb384b542018-01-15 01:08:33 -0800433 if (*rx_fifo == 0)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700434 {
Florin Corasb384b542018-01-15 01:08:33 -0800435 if (props->add_segment && !props->segment_type)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700436 {
437 if (added_a_segment)
438 {
Florin Corasc87c91d2017-08-16 19:55:49 -0700439 clib_warning ("added a segment, still can't allocate a fifo");
Florin Corasf03a59a2017-06-09 21:07:32 -0700440 clib_spinlock_unlock (&sm->lockp);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700441 return SESSION_ERROR_NEW_SEG_NO_SPACE;
442 }
443
Florin Corasb384b542018-01-15 01:08:33 -0800444 if (segment_manager_add_segment (sm))
Florin Corasa5464812017-04-19 13:00:05 -0700445 {
Florin Corasf03a59a2017-06-09 21:07:32 -0700446 clib_spinlock_unlock (&sm->lockp);
Florin Corasa5464812017-04-19 13:00:05 -0700447 return VNET_API_ERROR_URI_FIFO_CREATE_FAILED;
448 }
Florin Coras6cf30ad2017-04-04 23:08:23 -0700449
450 added_a_segment = 1;
451 goto again;
452 }
453 else
454 {
455 clib_warning ("No space to allocate fifos!");
Florin Corasf03a59a2017-06-09 21:07:32 -0700456 clib_spinlock_unlock (&sm->lockp);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700457 return SESSION_ERROR_NO_SPACE;
458 }
459 }
460
Florin Coras6cf30ad2017-04-04 23:08:23 -0700461 /* Backpointers to segment manager */
462 sm_index = segment_manager_index (sm);
Florin Corasb384b542018-01-15 01:08:33 -0800463 (*tx_fifo)->segment_manager = sm_index;
464 (*rx_fifo)->segment_manager = sm_index;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700465
Florin Corasa5464812017-04-19 13:00:05 -0700466 clib_spinlock_unlock (&sm->lockp);
467
468 if (added_a_segment)
Florin Corasc87c91d2017-08-16 19:55:49 -0700469 return application_add_segment_notify (sm->app_index,
470 *fifo_segment_index);
Florin Corasa5464812017-04-19 13:00:05 -0700471
Florin Coras6cf30ad2017-04-04 23:08:23 -0700472 return 0;
473}
474
475void
476segment_manager_dealloc_fifos (u32 svm_segment_index, svm_fifo_t * rx_fifo,
477 svm_fifo_t * tx_fifo)
478{
479 segment_manager_t *sm;
480 svm_fifo_segment_private_t *fifo_segment;
Florin Corasc87c91d2017-08-16 19:55:49 -0700481 u32 i, segment_index = ~0;
482 u8 is_first;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700483
Florin Corasa5464812017-04-19 13:00:05 -0700484 sm = segment_manager_get_if_valid (rx_fifo->segment_manager);
485
486 /* It's possible to have no segment manager if the session was removed
Florin Corasc87c91d2017-08-16 19:55:49 -0700487 * as result of a detach. */
Florin Corasa5464812017-04-19 13:00:05 -0700488 if (!sm)
489 return;
490
Florin Corasc87c91d2017-08-16 19:55:49 -0700491 fifo_segment = svm_fifo_segment_get_segment (svm_segment_index);
Dave Barach10d8cc62017-05-30 09:30:07 -0400492 svm_fifo_segment_free_fifo (fifo_segment, rx_fifo,
493 FIFO_SEGMENT_RX_FREELIST);
494 svm_fifo_segment_free_fifo (fifo_segment, tx_fifo,
495 FIFO_SEGMENT_TX_FREELIST);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700496
Florin Corasc87c91d2017-08-16 19:55:49 -0700497 /*
498 * Try to remove svm segment if it has no fifos. This can be done only if
499 * the segment is not the first in the segment manager or if it is first
500 * and it is not protected. Moreover, if the segment is first and the app
501 * has detached from the segment manager, remove the segment manager.
502 */
503 if (!svm_fifo_segment_has_fifos (fifo_segment))
Florin Coras6cf30ad2017-04-04 23:08:23 -0700504 {
Florin Corasc87c91d2017-08-16 19:55:49 -0700505 is_first = sm->segment_indices[0] == svm_segment_index;
506
507 /* Remove segment if it holds no fifos or first but not protected */
508 if (!is_first || !sm->first_is_protected)
509 {
510 /* Find the segment manager segment index */
511 for (i = 0; i < vec_len (sm->segment_indices); i++)
512 if (sm->segment_indices[i] == svm_segment_index)
513 {
514 segment_index = i;
515 break;
516 }
517 ASSERT (segment_index != (u32) ~ 0);
518 segment_manager_del_segment (sm, segment_index);
519 }
520
521 /* Remove segment manager if no sessions and detached from app */
Florin Coras9d063042017-09-14 03:08:00 -0400522 if (segment_manager_app_detached (sm)
523 && !segment_manager_has_fifos (sm))
Florin Corasc87c91d2017-08-16 19:55:49 -0700524 segment_manager_del (sm);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700525 }
526}
527
Florin Corasa5464812017-04-19 13:00:05 -0700528/**
529 * Allocates shm queue in the first segment
530 */
Florin Corase86a8ed2018-01-05 03:20:25 -0800531svm_queue_t *
Florin Corasa5464812017-04-19 13:00:05 -0700532segment_manager_alloc_queue (segment_manager_t * sm, u32 queue_size)
533{
534 ssvm_shared_header_t *sh;
535 svm_fifo_segment_private_t *segment;
Florin Corase86a8ed2018-01-05 03:20:25 -0800536 svm_queue_t *q;
Florin Corasa5464812017-04-19 13:00:05 -0700537 void *oldheap;
538
539 ASSERT (sm->segment_indices != 0);
540
Florin Corasc87c91d2017-08-16 19:55:49 -0700541 segment = svm_fifo_segment_get_segment (sm->segment_indices[0]);
Florin Corasa5464812017-04-19 13:00:05 -0700542 sh = segment->ssvm.sh;
543
544 oldheap = ssvm_push_heap (sh);
Florin Corase86a8ed2018-01-05 03:20:25 -0800545 q = svm_queue_init (queue_size,
546 sizeof (session_fifo_event_t), 0 /* consumer pid */ ,
547 0 /* signal when queue non-empty */ );
Florin Corasa5464812017-04-19 13:00:05 -0700548 ssvm_pop_heap (oldheap);
549 return q;
550}
551
552/**
553 * Frees shm queue allocated in the first segment
554 */
555void
Florin Corase86a8ed2018-01-05 03:20:25 -0800556segment_manager_dealloc_queue (segment_manager_t * sm, svm_queue_t * q)
Florin Corasa5464812017-04-19 13:00:05 -0700557{
558 ssvm_shared_header_t *sh;
559 svm_fifo_segment_private_t *segment;
560 void *oldheap;
561
562 ASSERT (sm->segment_indices != 0);
563
Florin Corasc87c91d2017-08-16 19:55:49 -0700564 segment = svm_fifo_segment_get_segment (sm->segment_indices[0]);
Florin Corasa5464812017-04-19 13:00:05 -0700565 sh = segment->ssvm.sh;
566
567 oldheap = ssvm_push_heap (sh);
Florin Corase86a8ed2018-01-05 03:20:25 -0800568 svm_queue_free (q);
Florin Corasa5464812017-04-19 13:00:05 -0700569 ssvm_pop_heap (oldheap);
570}
571
Florin Corasc87c91d2017-08-16 19:55:49 -0700572static clib_error_t *
573segment_manager_show_fn (vlib_main_t * vm, unformat_input_t * input,
574 vlib_cli_command_t * cmd)
575{
576 svm_fifo_segment_private_t *segments, *seg;
577 segment_manager_t *sm;
Florin Corasb384b542018-01-15 01:08:33 -0800578 u8 show_segments = 0, verbose = 0;
Florin Corasc87c91d2017-08-16 19:55:49 -0700579 uword address;
580 u64 size;
Dave Barach91f3e742017-09-01 19:12:11 -0400581 u32 active_fifos;
582 u32 free_fifos;
583
Florin Corasc87c91d2017-08-16 19:55:49 -0700584 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
585 {
586 if (unformat (input, "segments"))
587 show_segments = 1;
588 else if (unformat (input, "verbose"))
589 verbose = 1;
590 else
591 return clib_error_return (0, "unknown input `%U'",
592 format_unformat_error, input);
593 }
594 vlib_cli_output (vm, "%d segment managers allocated",
595 pool_elts (segment_managers));
596 if (verbose && pool_elts (segment_managers))
597 {
598 vlib_cli_output (vm, "%-10s%=15s%=12s", "Index", "App Index",
599 "Segments");
600
601 /* *INDENT-OFF* */
602 pool_foreach (sm, segment_managers, ({
603 vlib_cli_output (vm, "%-10d%=15d%=12d", segment_manager_index(sm),
604 sm->app_index, vec_len (sm->segment_indices));
605 }));
606 /* *INDENT-ON* */
607
608 }
609 if (show_segments)
610 {
611 segments = svm_fifo_segment_segments_pool ();
612 vlib_cli_output (vm, "%d svm fifo segments allocated",
613 pool_elts (segments));
Florin Corasb384b542018-01-15 01:08:33 -0800614 vlib_cli_output (vm, "%-15s%10s%15s%15s%15s%15s", "Name", "Type",
Dave Barach91f3e742017-09-01 19:12:11 -0400615 "HeapSize (M)", "ActiveFifos", "FreeFifos", "Address");
Florin Corasc87c91d2017-08-16 19:55:49 -0700616
617 /* *INDENT-OFF* */
618 pool_foreach (seg, segments, ({
Florin Corasb384b542018-01-15 01:08:33 -0800619 svm_fifo_segment_info (seg, &address, &size);
Dave Barach91f3e742017-09-01 19:12:11 -0400620 active_fifos = svm_fifo_segment_num_fifos (seg);
621 free_fifos = svm_fifo_segment_num_free_fifos (seg, ~0 /* size */);
Florin Corasb384b542018-01-15 01:08:33 -0800622 vlib_cli_output (vm, "%-15v%10U%15llu%15u%15u%15llx",
623 ssvm_name (&seg->ssvm), format_svm_fifo_segment_type,
624 seg, size >> 20ULL, active_fifos, free_fifos,
625 address);
Dave Barach91f3e742017-09-01 19:12:11 -0400626 if (verbose)
Florin Corasb384b542018-01-15 01:08:33 -0800627 vlib_cli_output (vm, "%U", format_svm_fifo_segment, seg, verbose);
Florin Corasc87c91d2017-08-16 19:55:49 -0700628 }));
629 /* *INDENT-ON* */
630
631 }
632 return 0;
633}
634
Florin Corasad0c77f2017-11-09 18:00:15 -0800635/* *INDENT-OFF* */
Florin Corasc87c91d2017-08-16 19:55:49 -0700636VLIB_CLI_COMMAND (segment_manager_show_command, static) =
637{
638 .path = "show segment-manager",
Dave Barach91f3e742017-09-01 19:12:11 -0400639 .short_help = "show segment-manager [segments][verbose]",
Florin Corasc87c91d2017-08-16 19:55:49 -0700640 .function = segment_manager_show_fn,
641};
642/* *INDENT-ON* */
643
Florin Coras6cf30ad2017-04-04 23:08:23 -0700644/*
645 * fd.io coding-style-patch-verification: ON
646 *
647 * Local Variables:
648 * eval: (c-set-style "gnu")
649 * End:
650 */