session: separate local session logic
[vpp.git] / src / vnet / session / segment_manager.c
1 /*
2  * Copyright (c) 2017-2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vnet/session/segment_manager.h>
17 #include <vnet/session/session.h>
18 #include <vnet/session/application.h>
19 #include <vnet/session/application_local.h>
20
21 segment_manager_main_t segment_manager_main;
22
23 /**
24  * Counter used to build segment names
25  */
26 static u32 segment_name_counter = 0;
27
28 /**
29  * Default fifo and segment size. TODO config.
30  */
31 static u32 default_fifo_size = 1 << 12;
32 static u32 default_segment_size = 1 << 20;
33 static u32 default_app_evt_queue_size = 128;
34
35 segment_manager_properties_t *
36 segment_manager_properties_get (segment_manager_t * sm)
37 {
38   app_worker_t *app_wrk = app_worker_get (sm->app_wrk_index);
39   return application_get_segment_manager_properties (app_wrk->app_index);
40 }
41
42 segment_manager_properties_t *
43 segment_manager_properties_init (segment_manager_properties_t * props)
44 {
45   props->add_segment_size = default_segment_size;
46   props->rx_fifo_size = default_fifo_size;
47   props->tx_fifo_size = default_fifo_size;
48   props->evt_q_size = default_app_evt_queue_size;
49   return props;
50 }
51
52 static u8
53 segment_manager_app_detached (segment_manager_t * sm)
54 {
55   return (sm->app_wrk_index == SEGMENT_MANAGER_INVALID_APP_INDEX);
56 }
57
58 void
59 segment_manager_app_detach (segment_manager_t * sm)
60 {
61   sm->app_wrk_index = SEGMENT_MANAGER_INVALID_APP_INDEX;
62 }
63
64 always_inline u32
65 segment_manager_segment_index (segment_manager_t * sm,
66                                svm_fifo_segment_private_t * seg)
67 {
68   return (seg - sm->segments);
69 }
70
71 /**
72  * Remove segment without lock
73  */
74 void
75 segment_manager_del_segment (segment_manager_t * sm,
76                              svm_fifo_segment_private_t * fs)
77 {
78   segment_manager_main_t *smm = &segment_manager_main;
79
80   if (ssvm_type (&fs->ssvm) != SSVM_SEGMENT_PRIVATE)
81     clib_valloc_free (&smm->va_allocator, fs->ssvm.requested_va);
82
83   ssvm_delete (&fs->ssvm);
84
85   if (CLIB_DEBUG)
86     clib_memset (fs, 0xfb, sizeof (*fs));
87   pool_put (sm->segments, fs);
88 }
89
90 /**
91  * Removes segment after acquiring writer lock
92  */
93 static inline void
94 segment_manager_lock_and_del_segment (segment_manager_t * sm, u32 fs_index)
95 {
96   svm_fifo_segment_private_t *fs;
97   u8 is_prealloc;
98
99   clib_rwlock_writer_lock (&sm->segments_rwlock);
100   fs = segment_manager_get_segment (sm, fs_index);
101   is_prealloc = svm_fifo_segment_flags (fs) & FIFO_SEGMENT_F_IS_PREALLOCATED;
102   if (is_prealloc && !segment_manager_app_detached (sm))
103     {
104       clib_rwlock_writer_unlock (&sm->segments_rwlock);
105       return;
106     }
107
108   segment_manager_del_segment (sm, fs);
109   clib_rwlock_writer_unlock (&sm->segments_rwlock);
110 }
111
112 /**
113  * Reads a segment from the segment manager's pool without lock
114  */
115 svm_fifo_segment_private_t *
116 segment_manager_get_segment (segment_manager_t * sm, u32 segment_index)
117 {
118   return pool_elt_at_index (sm->segments, segment_index);
119 }
120
121 u64
122 segment_manager_segment_handle (segment_manager_t * sm,
123                                 svm_fifo_segment_private_t * segment)
124 {
125   u32 segment_index = segment_manager_segment_index (sm, segment);
126   return (((u64) segment_manager_index (sm) << 32) | segment_index);
127 }
128
129 void
130 segment_manager_parse_segment_handle (u64 segment_handle, u32 * sm_index,
131                                       u32 * segment_index)
132 {
133   *sm_index = segment_handle >> 32;
134   *segment_index = segment_handle & 0xFFFFFFFF;
135 }
136
137 svm_fifo_segment_private_t *
138 segment_manager_get_segment_w_handle (u64 segment_handle)
139 {
140   u32 sm_index, segment_index;
141   segment_manager_t *sm;
142
143   segment_manager_parse_segment_handle (segment_handle, &sm_index,
144                                         &segment_index);
145   sm = segment_manager_get (sm_index);
146   if (!sm || pool_is_free_index (sm->segments, segment_index))
147     return 0;
148   return pool_elt_at_index (sm->segments, segment_index);
149 }
150
151 /**
152  * Reads a segment from the segment manager's pool and acquires reader lock
153  *
154  * Caller must drop the reader's lock by calling
155  * @ref segment_manager_segment_reader_unlock once it finishes working with
156  * the segment.
157  */
158 svm_fifo_segment_private_t *
159 segment_manager_get_segment_w_lock (segment_manager_t * sm, u32 segment_index)
160 {
161   clib_rwlock_reader_lock (&sm->segments_rwlock);
162   return pool_elt_at_index (sm->segments, segment_index);
163 }
164
165 void
166 segment_manager_segment_reader_unlock (segment_manager_t * sm)
167 {
168   ASSERT (sm->segments_rwlock->n_readers > 0);
169   clib_rwlock_reader_unlock (&sm->segments_rwlock);
170 }
171
172 void
173 segment_manager_segment_writer_unlock (segment_manager_t * sm)
174 {
175   clib_rwlock_writer_unlock (&sm->segments_rwlock);
176 }
177
178 /**
179  * Adds segment to segment manager's pool
180  *
181  * If needed a writer's lock is acquired before allocating a new segment
182  * to avoid affecting any of the segments pool readers.
183  */
184 int
185 segment_manager_add_segment (segment_manager_t * sm, u32 segment_size)
186 {
187   segment_manager_main_t *smm = &segment_manager_main;
188   u32 rnd_margin = 128 << 10, seg_index, page_size;
189   segment_manager_properties_t *props;
190   uword baseva = (uword) ~ 0ULL, alloc_size;
191   svm_fifo_segment_private_t *seg;
192   u8 *seg_name;
193   int rv;
194
195   props = segment_manager_properties_get (sm);
196
197   /* Not configured for addition of new segments and not first */
198   if (!props->add_segment && !segment_size)
199     {
200       clib_warning ("cannot allocate new segment");
201       return VNET_API_ERROR_INVALID_VALUE;
202     }
203
204   /*
205    * Allocate fifo segment and lock if needed
206    */
207   if (vlib_num_workers ())
208     {
209       clib_rwlock_writer_lock (&sm->segments_rwlock);
210       pool_get (sm->segments, seg);
211     }
212   else
213     {
214       pool_get (sm->segments, seg);
215     }
216   clib_memset (seg, 0, sizeof (*seg));
217
218   /*
219    * Initialize ssvm segment and svm fifo private header
220    */
221   segment_size = segment_size ? segment_size : props->add_segment_size;
222   page_size = clib_mem_get_page_size ();
223   segment_size = (segment_size + page_size - 1) & ~(page_size - 1);
224   if (props->segment_type != SSVM_SEGMENT_PRIVATE)
225     {
226       seg_name = format (0, "%d-%d%c", getpid (), segment_name_counter++, 0);
227       alloc_size = (uword) segment_size + rnd_margin;
228       baseva = clib_valloc_alloc (&smm->va_allocator, alloc_size, 0);
229       if (!baseva)
230         {
231           clib_warning ("out of space for segments");
232           return -1;
233         }
234     }
235   else
236     seg_name = format (0, "%s%c", "process-private-segment", 0);
237
238   seg->ssvm.ssvm_size = segment_size;
239   seg->ssvm.name = seg_name;
240   seg->ssvm.requested_va = baseva;
241
242   if ((rv = ssvm_master_init (&seg->ssvm, props->segment_type)))
243     {
244       clib_warning ("svm_master_init ('%v', %u) failed", seg_name,
245                     segment_size);
246
247       if (props->segment_type != SSVM_SEGMENT_PRIVATE)
248         clib_valloc_free (&smm->va_allocator, baseva);
249       pool_put (sm->segments, seg);
250       return (rv);
251     }
252
253   svm_fifo_segment_init (seg);
254
255   /*
256    * Save segment index before dropping lock, if any held
257    */
258   seg_index = seg - sm->segments;
259
260   if (vlib_num_workers ())
261     clib_rwlock_writer_unlock (&sm->segments_rwlock);
262
263   return seg_index;
264 }
265
266 segment_manager_t *
267 segment_manager_new ()
268 {
269   segment_manager_main_t *smm = &segment_manager_main;
270   segment_manager_t *sm;
271   pool_get (smm->segment_managers, sm);
272   clib_memset (sm, 0, sizeof (*sm));
273   clib_rwlock_init (&sm->segments_rwlock);
274   return sm;
275 }
276
277 /**
278  * Initializes segment manager based on options provided.
279  * Returns error if ssvm segment(s) allocation fails.
280  */
281 int
282 segment_manager_init (segment_manager_t * sm, u32 first_seg_size,
283                       u32 prealloc_fifo_pairs)
284 {
285   u32 rx_fifo_size, tx_fifo_size, pair_size;
286   u32 rx_rounded_data_size, tx_rounded_data_size;
287   u64 approx_total_size, max_seg_size = ((u64) 1 << 32) - (128 << 10);
288   segment_manager_properties_t *props;
289   svm_fifo_segment_private_t *segment;
290   u32 approx_segment_count;
291   int seg_index, i;
292
293   props = segment_manager_properties_get (sm);
294   first_seg_size = clib_max (first_seg_size, default_segment_size);
295
296   if (prealloc_fifo_pairs)
297     {
298       /* Figure out how many segments should be preallocated */
299       rx_rounded_data_size = (1 << (max_log2 (props->rx_fifo_size)));
300       tx_rounded_data_size = (1 << (max_log2 (props->tx_fifo_size)));
301
302       rx_fifo_size = sizeof (svm_fifo_t) + rx_rounded_data_size;
303       tx_fifo_size = sizeof (svm_fifo_t) + tx_rounded_data_size;
304       pair_size = rx_fifo_size + tx_fifo_size;
305
306       approx_total_size = (u64) prealloc_fifo_pairs *pair_size;
307       if (first_seg_size > approx_total_size)
308         max_seg_size = first_seg_size;
309       approx_segment_count = (approx_total_size + (max_seg_size - 1))
310         / max_seg_size;
311
312       /* Allocate the segments */
313       for (i = 0; i < approx_segment_count + 1; i++)
314         {
315           seg_index = segment_manager_add_segment (sm, max_seg_size);
316           if (seg_index < 0)
317             {
318               clib_warning ("Failed to preallocate segment %d", i);
319               return seg_index;
320             }
321
322           segment = segment_manager_get_segment (sm, seg_index);
323           if (i == 0)
324             sm->event_queue = segment_manager_alloc_queue (segment, props);
325
326           svm_fifo_segment_preallocate_fifo_pairs (segment,
327                                                    props->rx_fifo_size,
328                                                    props->tx_fifo_size,
329                                                    &prealloc_fifo_pairs);
330           svm_fifo_segment_flags (segment) = FIFO_SEGMENT_F_IS_PREALLOCATED;
331           if (prealloc_fifo_pairs == 0)
332             break;
333         }
334     }
335   else
336     {
337       seg_index = segment_manager_add_segment (sm, first_seg_size);
338       if (seg_index)
339         {
340           clib_warning ("Failed to allocate segment");
341           return seg_index;
342         }
343       segment = segment_manager_get_segment (sm, seg_index);
344       sm->event_queue = segment_manager_alloc_queue (segment, props);
345     }
346
347   return 0;
348 }
349
350 u8
351 segment_manager_has_fifos (segment_manager_t * sm)
352 {
353   svm_fifo_segment_private_t *seg;
354   u8 first = 1;
355
356   /* *INDENT-OFF* */
357   segment_manager_foreach_segment_w_lock (seg, sm, ({
358     if (CLIB_DEBUG && !first && !svm_fifo_segment_has_fifos (seg)
359         && !(svm_fifo_segment_flags (seg) & FIFO_SEGMENT_F_IS_PREALLOCATED))
360       {
361         clib_warning ("segment %d has no fifos!",
362                       segment_manager_segment_index (sm, seg));
363         first = 0;
364       }
365     if (svm_fifo_segment_has_fifos (seg))
366       {
367         segment_manager_segment_reader_unlock (sm);
368         return 1;
369       }
370   }));
371   /* *INDENT-ON* */
372
373   return 0;
374 }
375
376 /**
377  * Initiate disconnects for all sessions 'owned' by a segment manager
378  */
379 void
380 segment_manager_del_sessions (segment_manager_t * sm)
381 {
382   svm_fifo_segment_private_t *fifo_segment;
383   session_t *session;
384   svm_fifo_t *fifo;
385
386   ASSERT (pool_elts (sm->segments) != 0);
387
388   /* Across all fifo segments used by the server */
389   /* *INDENT-OFF* */
390   segment_manager_foreach_segment_w_lock (fifo_segment, sm, ({
391     fifo = svm_fifo_segment_get_fifo_list (fifo_segment);
392
393     /*
394      * Remove any residual sessions from the session lookup table
395      * Don't bother deleting the individual fifos, we're going to
396      * throw away the fifo segment in a minute.
397      */
398     while (fifo)
399       {
400         if (fifo->ct_session_index != SVM_FIFO_INVALID_SESSION_INDEX)
401           {
402             svm_fifo_t *next = fifo->next;
403             app_worker_local_session_disconnect_w_index (sm->app_wrk_index,
404                                                           fifo->ct_session_index);
405             fifo = next;
406             continue;
407           }
408         session = session_get (fifo->master_session_index,
409                                fifo->master_thread_index);
410         session_close (session);
411         fifo = fifo->next;
412       }
413
414     /* Instead of removing the segment, test when cleaning up disconnected
415      * sessions if the segment can be removed.
416      */
417   }));
418   /* *INDENT-ON* */
419 }
420
421 /**
422  * Removes segment manager.
423  *
424  * Since the fifos allocated in the segment keep backpointers to the sessions
425  * prior to removing the segment, we call session disconnect. This
426  * subsequently propagates into transport.
427  */
428 void
429 segment_manager_del (segment_manager_t * sm)
430 {
431   segment_manager_main_t *smm = &segment_manager_main;
432   svm_fifo_segment_private_t *fifo_segment;
433
434   ASSERT (!segment_manager_has_fifos (sm)
435           && segment_manager_app_detached (sm));
436
437   /* If we have empty preallocated segments that haven't been removed, remove
438    * them now. Apart from that, the first segment in the first segment manager
439    * is not removed when all fifos are removed. It can only be removed when
440    * the manager is explicitly deleted/detached by the app. */
441   clib_rwlock_writer_lock (&sm->segments_rwlock);
442
443   /* *INDENT-OFF* */
444   pool_foreach (fifo_segment, sm->segments, ({
445     segment_manager_del_segment (sm, fifo_segment);
446   }));
447   /* *INDENT-ON* */
448
449   clib_rwlock_writer_unlock (&sm->segments_rwlock);
450
451   clib_rwlock_free (&sm->segments_rwlock);
452   if (CLIB_DEBUG)
453     clib_memset (sm, 0xfe, sizeof (*sm));
454   pool_put (smm->segment_managers, sm);
455 }
456
457 void
458 segment_manager_init_del (segment_manager_t * sm)
459 {
460   segment_manager_app_detach (sm);
461   if (segment_manager_has_fifos (sm))
462     segment_manager_del_sessions (sm);
463   else
464     {
465       ASSERT (!sm->first_is_protected || segment_manager_app_detached (sm));
466       segment_manager_del (sm);
467     }
468 }
469
470 int
471 segment_manager_try_alloc_fifos (svm_fifo_segment_private_t * fifo_segment,
472                                  u32 rx_fifo_size, u32 tx_fifo_size,
473                                  svm_fifo_t ** rx_fifo, svm_fifo_t ** tx_fifo)
474 {
475   rx_fifo_size = clib_max (rx_fifo_size, default_fifo_size);
476   *rx_fifo = svm_fifo_segment_alloc_fifo (fifo_segment, rx_fifo_size,
477                                           FIFO_SEGMENT_RX_FREELIST);
478
479   tx_fifo_size = clib_max (tx_fifo_size, default_fifo_size);
480   *tx_fifo = svm_fifo_segment_alloc_fifo (fifo_segment, tx_fifo_size,
481                                           FIFO_SEGMENT_TX_FREELIST);
482
483   if (*rx_fifo == 0)
484     {
485       /* This would be very odd, but handle it... */
486       if (*tx_fifo != 0)
487         {
488           svm_fifo_segment_free_fifo (fifo_segment, *tx_fifo,
489                                       FIFO_SEGMENT_TX_FREELIST);
490           *tx_fifo = 0;
491         }
492       return -1;
493     }
494   if (*tx_fifo == 0)
495     {
496       if (*rx_fifo != 0)
497         {
498           svm_fifo_segment_free_fifo (fifo_segment, *rx_fifo,
499                                       FIFO_SEGMENT_RX_FREELIST);
500           *rx_fifo = 0;
501         }
502       return -1;
503     }
504
505   return 0;
506 }
507
508 int
509 segment_manager_alloc_session_fifos (segment_manager_t * sm,
510                                      svm_fifo_t ** rx_fifo,
511                                      svm_fifo_t ** tx_fifo,
512                                      u32 * fifo_segment_index)
513 {
514   svm_fifo_segment_private_t *fifo_segment = 0;
515   int alloc_fail = 1, rv = 0, new_fs_index;
516   segment_manager_properties_t *props;
517   u8 added_a_segment = 0;
518   u64 segment_handle;
519   u32 sm_index;
520
521   props = segment_manager_properties_get (sm);
522
523   /*
524    * Find the first free segment to allocate the fifos in
525    */
526
527   /* *INDENT-OFF* */
528   segment_manager_foreach_segment_w_lock (fifo_segment, sm, ({
529     alloc_fail = segment_manager_try_alloc_fifos (fifo_segment,
530                                                   props->rx_fifo_size,
531                                                   props->tx_fifo_size,
532                                                   rx_fifo, tx_fifo);
533     /* Exit with lock held, drop it after notifying app */
534     if (!alloc_fail)
535       goto alloc_success;
536   }));
537   /* *INDENT-ON* */
538
539 alloc_check:
540
541   if (!alloc_fail)
542     {
543
544     alloc_success:
545
546       ASSERT (rx_fifo && tx_fifo);
547       sm_index = segment_manager_index (sm);
548       *fifo_segment_index = segment_manager_segment_index (sm, fifo_segment);
549       (*tx_fifo)->segment_manager = sm_index;
550       (*rx_fifo)->segment_manager = sm_index;
551       (*tx_fifo)->segment_index = *fifo_segment_index;
552       (*rx_fifo)->segment_index = *fifo_segment_index;
553
554       if (added_a_segment)
555         {
556           segment_handle = segment_manager_segment_handle (sm, fifo_segment);
557           rv = app_worker_add_segment_notify (sm->app_wrk_index,
558                                               segment_handle);
559         }
560       /* Drop the lock after app is notified */
561       segment_manager_segment_reader_unlock (sm);
562       return rv;
563     }
564
565   /*
566    * Allocation failed, see if we can add a new segment
567    */
568   if (props->add_segment)
569     {
570       if (added_a_segment)
571         {
572           clib_warning ("Added a segment, still can't allocate a fifo");
573           segment_manager_segment_reader_unlock (sm);
574           return SESSION_ERROR_NEW_SEG_NO_SPACE;
575         }
576       if ((new_fs_index = segment_manager_add_segment (sm, 0)) < 0)
577         {
578           clib_warning ("Failed to add new segment");
579           return SESSION_ERROR_SEG_CREATE;
580         }
581       fifo_segment = segment_manager_get_segment_w_lock (sm, new_fs_index);
582       alloc_fail = segment_manager_try_alloc_fifos (fifo_segment,
583                                                     props->rx_fifo_size,
584                                                     props->tx_fifo_size,
585                                                     rx_fifo, tx_fifo);
586       added_a_segment = 1;
587       goto alloc_check;
588     }
589   else
590     {
591       clib_warning ("Can't add new seg and no space to allocate fifos!");
592       return SESSION_ERROR_NO_SPACE;
593     }
594 }
595
596 void
597 segment_manager_dealloc_fifos (u32 segment_index, svm_fifo_t * rx_fifo,
598                                svm_fifo_t * tx_fifo)
599 {
600   svm_fifo_segment_private_t *fifo_segment;
601   segment_manager_t *sm;
602
603   if (!rx_fifo || !tx_fifo)
604     return;
605
606   /* It's possible to have no segment manager if the session was removed
607    * as result of a detach. */
608   if (!(sm = segment_manager_get_if_valid (rx_fifo->segment_manager)))
609     return;
610
611   fifo_segment = segment_manager_get_segment_w_lock (sm, segment_index);
612   svm_fifo_segment_free_fifo (fifo_segment, rx_fifo,
613                               FIFO_SEGMENT_RX_FREELIST);
614   svm_fifo_segment_free_fifo (fifo_segment, tx_fifo,
615                               FIFO_SEGMENT_TX_FREELIST);
616
617   /*
618    * Try to remove svm segment if it has no fifos. This can be done only if
619    * the segment is not the first in the segment manager or if it is first
620    * and it is not protected. Moreover, if the segment is first and the app
621    * has detached from the segment manager, remove the segment manager.
622    */
623   if (!svm_fifo_segment_has_fifos (fifo_segment))
624     {
625       segment_manager_segment_reader_unlock (sm);
626
627       /* Remove segment if it holds no fifos or first but not protected */
628       if (segment_index != 0 || !sm->first_is_protected)
629         segment_manager_lock_and_del_segment (sm, segment_index);
630
631       /* Remove segment manager if no sessions and detached from app */
632       if (segment_manager_app_detached (sm)
633           && !segment_manager_has_fifos (sm))
634         {
635           segment_manager_del (sm);
636         }
637     }
638   else
639     segment_manager_segment_reader_unlock (sm);
640 }
641
642 u32
643 segment_manager_evt_q_expected_size (u32 q_len)
644 {
645   u32 fifo_evt_size, notif_q_size, q_hdrs;
646   u32 msg_q_sz, fifo_evt_ring_sz, session_ntf_ring_sz;
647
648   fifo_evt_size = 1 << max_log2 (sizeof (session_event_t));
649   notif_q_size = clib_max (16, q_len >> 4);
650
651   msg_q_sz = q_len * sizeof (svm_msg_q_msg_t);
652   fifo_evt_ring_sz = q_len * fifo_evt_size;
653   session_ntf_ring_sz = notif_q_size * 256;
654   q_hdrs = sizeof (svm_queue_t) + sizeof (svm_msg_q_t);
655
656   return (msg_q_sz + fifo_evt_ring_sz + session_ntf_ring_sz + q_hdrs);
657 }
658
659 /**
660  * Allocates shm queue in the first segment
661  *
662  * Must be called with lock held
663  */
664 svm_msg_q_t *
665 segment_manager_alloc_queue (svm_fifo_segment_private_t * segment,
666                              segment_manager_properties_t * props)
667 {
668   u32 fifo_evt_size, session_evt_size = 256, notif_q_size;
669   svm_msg_q_cfg_t _cfg, *cfg = &_cfg;
670   svm_msg_q_t *q;
671   void *oldheap;
672
673   fifo_evt_size = sizeof (session_event_t);
674   notif_q_size = clib_max (16, props->evt_q_size >> 4);
675   /* *INDENT-OFF* */
676   svm_msg_q_ring_cfg_t rc[SESSION_MQ_N_RINGS] = {
677     {props->evt_q_size, fifo_evt_size, 0},
678     {notif_q_size, session_evt_size, 0}
679   };
680   /* *INDENT-ON* */
681   cfg->consumer_pid = 0;
682   cfg->n_rings = 2;
683   cfg->q_nitems = props->evt_q_size;
684   cfg->ring_cfgs = rc;
685
686   oldheap = ssvm_push_heap (segment->ssvm.sh);
687   q = svm_msg_q_alloc (cfg);
688   ssvm_pop_heap (oldheap);
689
690   if (props->use_mq_eventfd)
691     {
692       if (svm_msg_q_alloc_producer_eventfd (q))
693         clib_warning ("failed to alloc eventfd");
694     }
695   return q;
696 }
697
698 /**
699  * Frees shm queue allocated in the first segment
700  */
701 void
702 segment_manager_dealloc_queue (segment_manager_t * sm, svm_queue_t * q)
703 {
704   svm_fifo_segment_private_t *segment;
705   ssvm_shared_header_t *sh;
706   void *oldheap;
707
708   ASSERT (!pool_is_free_index (sm->segments, 0));
709
710   segment = segment_manager_get_segment_w_lock (sm, 0);
711   sh = segment->ssvm.sh;
712
713   oldheap = ssvm_push_heap (sh);
714   svm_queue_free (q);
715   ssvm_pop_heap (oldheap);
716   segment_manager_segment_reader_unlock (sm);
717 }
718
719 /*
720  * Init segment vm address allocator
721  */
722 void
723 segment_manager_main_init (segment_manager_main_init_args_t * a)
724 {
725   segment_manager_main_t *sm = &segment_manager_main;
726   clib_valloc_chunk_t _ip, *ip = &_ip;
727
728   ip->baseva = a->baseva;
729   ip->size = a->size;
730
731   clib_valloc_init (&sm->va_allocator, ip, 1 /* lock */ );
732 }
733
734 static clib_error_t *
735 segment_manager_show_fn (vlib_main_t * vm, unformat_input_t * input,
736                          vlib_cli_command_t * cmd)
737 {
738   segment_manager_main_t *smm = &segment_manager_main;
739   svm_fifo_segment_private_t *seg;
740   segment_manager_t *sm;
741   u8 show_segments = 0, verbose = 0;
742   char *address;
743   size_t size;
744   u32 active_fifos;
745   u32 free_fifos;
746
747   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
748     {
749       if (unformat (input, "segments"))
750         show_segments = 1;
751       else if (unformat (input, "verbose"))
752         verbose = 1;
753       else
754         return clib_error_return (0, "unknown input `%U'",
755                                   format_unformat_error, input);
756     }
757   vlib_cli_output (vm, "%d segment managers allocated",
758                    pool_elts (smm->segment_managers));
759   if (verbose && pool_elts (smm->segment_managers))
760     {
761       vlib_cli_output (vm, "%-10s%=15s%=12s", "Index", "App Index",
762                        "Segments");
763
764       /* *INDENT-OFF* */
765       pool_foreach (sm, smm->segment_managers, ({
766         vlib_cli_output (vm, "%-10d%=15d%=12d", segment_manager_index (sm),
767                            sm->app_wrk_index, pool_elts (sm->segments));
768       }));
769       /* *INDENT-ON* */
770
771     }
772   if (show_segments)
773     {
774       vlib_cli_output (vm, "%-15s%15s%15s%15s%15s%15s", "Name", "Type",
775                        "HeapSize (M)", "ActiveFifos", "FreeFifos", "Address");
776
777       /* *INDENT-OFF* */
778       pool_foreach (sm, smm->segment_managers, ({
779           segment_manager_foreach_segment_w_lock (seg, sm, ({
780             svm_fifo_segment_info (seg, &address, &size);
781             active_fifos = svm_fifo_segment_num_fifos (seg);
782             free_fifos = svm_fifo_segment_num_free_fifos (seg, ~0 /* size */);
783             vlib_cli_output (vm, "%-15v%15U%15llu%15u%15u%15llx",
784                              ssvm_name (&seg->ssvm), format_svm_fifo_segment_type,
785                              seg, size >> 20ULL, active_fifos, free_fifos,
786                              address);
787             if (verbose)
788               vlib_cli_output (vm, "%U", format_svm_fifo_segment, seg, verbose);
789           }));
790       }));
791       /* *INDENT-ON* */
792
793     }
794   return 0;
795 }
796
797 /* *INDENT-OFF* */
798 VLIB_CLI_COMMAND (segment_manager_show_command, static) =
799 {
800   .path = "show segment-manager",
801   .short_help = "show segment-manager [segments][verbose]",
802   .function = segment_manager_show_fn,
803 };
804 /* *INDENT-ON* */
805
806 /*
807  * fd.io coding-style-patch-verification: ON
808  *
809  * Local Variables:
810  * eval: (c-set-style "gnu")
811  * End:
812  */