FD.io VPP  v17.07-30-g839fa73
Vector Packet Processing
segment_manager.c
Go to the documentation of this file.
1 /*
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 
17 #include <vnet/session/session.h>
19 
20 /**
21  * Counter used to build segment names
22  */
24 
25 /**
26  * Pool of segment managers
27  */
29 
30 /**
31  * Process private segment index
32  */
34 
35 /**
36  * Default fifo and segment size. TODO config.
37  */
40 
41 void
43 {
45  s = svm_fifo_get_segment (index);
46  *name = s->h->segment_name;
47  *size = s->ssvm.ssvm_size;
48 }
49 
50 always_inline int
52  u8 * segment_name)
53 {
54  svm_fifo_segment_create_args_t _ca, *ca = &_ca;
55  int rv;
56 
57  memset (ca, 0, sizeof (*ca));
58 
59  ca->segment_name = (char *) segment_name;
60  ca->segment_size = segment_size;
61  ca->rx_fifo_size = sm->properties->rx_fifo_size;
62  ca->tx_fifo_size = sm->properties->tx_fifo_size;
63  ca->preallocated_fifo_pairs = sm->properties->preallocated_fifo_pairs;
64 
65  rv = svm_fifo_segment_create (ca);
66  if (rv)
67  {
68  clib_warning ("svm_fifo_segment_create ('%s', %d) failed",
69  ca->segment_name, ca->segment_size);
70  vec_free (segment_name);
71  return VNET_API_ERROR_SVM_SEGMENT_CREATE_FAIL;
72  }
73 
74  vec_add1 (sm->segment_indices, ca->new_segment_index);
75 
76  return 0;
77 }
78 
79 int
81 {
82  u8 *segment_name;
83  svm_fifo_segment_create_args_t _ca, *ca = &_ca;
84  u32 add_segment_size;
85  int rv;
86 
87  memset (ca, 0, sizeof (*ca));
88  segment_name = format (0, "%d-%d%c", getpid (), segment_name_counter++, 0);
89  add_segment_size = sm->properties->add_segment_size ?
90  sm->properties->add_segment_size : default_segment_size;
91 
92  rv = session_manager_add_segment_i (sm, add_segment_size, segment_name);
93  vec_free (segment_name);
94  return rv;
95 }
96 
97 int
99 {
100  u8 *segment_name;
101  int rv;
102 
103  segment_name = format (0, "%d-%d%c", getpid (), segment_name_counter++, 0);
104  rv = session_manager_add_segment_i (sm, segment_size, segment_name);
105  vec_free (segment_name);
106  return rv;
107 }
108 
109 static void
112 {
114 
115  if (private_segment_index != ~0)
116  return;
117 
118  memset (a, 0, sizeof (*a));
119  a->segment_name = "process-private-segment";
120  a->segment_size = ~0;
121  a->new_segment_index = ~0;
122  a->rx_fifo_size = props->rx_fifo_size;
123  a->tx_fifo_size = props->tx_fifo_size;
124  a->preallocated_fifo_pairs = props->preallocated_fifo_pairs;
125 
127  clib_warning ("Failed to create process private segment");
128 
129  private_segment_index = a->new_segment_index;
130  ASSERT (private_segment_index != ~0);
131 }
132 
133 /**
134  * Initializes segment manager based on options provided.
135  * Returns error if svm segment allocation fails.
136  */
137 int
139  segment_manager_properties_t * properties,
140  u32 first_seg_size)
141 {
142  int rv;
143 
144  /* app allocates these */
145  sm->properties = properties;
146 
147  first_seg_size = first_seg_size > 0 ? first_seg_size : default_segment_size;
148 
149  if (sm->properties->use_private_segment == 0)
150  {
151  rv = session_manager_add_first_segment (sm, first_seg_size);
152  if (rv)
153  {
154  clib_warning ("Failed to allocate segment");
155  return rv;
156  }
157  }
158  else
159  {
160  if (private_segment_index == ~0)
162  ASSERT (private_segment_index != ~0);
163  vec_add1 (sm->segment_indices, private_segment_index);
164  }
165 
166  clib_spinlock_init (&sm->lockp);
167  return 0;
168 }
169 
170 /**
171  * Removes segment manager.
172  *
173  * Since the fifos allocated in the segment keep backpointers to the sessions
174  * prior to removing the segment, we call session disconnect. This
175  * subsequently propages into transport.
176  */
177 void
179 {
180  int j;
181 
182  /* Across all fifo segments used by the server */
183  for (j = 0; j < vec_len (sm->segment_indices); j++)
184  {
185  svm_fifo_segment_private_t *fifo_segment;
186  svm_fifo_t *fifo;
187 
188  /* Vector of fifos allocated in the segment */
189  fifo_segment = svm_fifo_get_segment (sm->segment_indices[j]);
190  fifo = svm_fifo_segment_get_fifo_list (fifo_segment);
191 
192  /*
193  * Remove any residual sessions from the session lookup table
194  * Don't bother deleting the individual fifos, we're going to
195  * throw away the fifo segment in a minute.
196  */
197  while (fifo)
198  {
199  u32 session_index, thread_index;
200  stream_session_t *session;
201 
202  session_index = fifo->master_session_index;
203  thread_index = fifo->master_thread_index;
204 
205  session = stream_session_get (session_index, thread_index);
206 
207  /* Instead of directly removing the session call disconnect */
210  thread_index);
211  fifo = fifo->next;
212  }
213 
214  /* Instead of removing the segment, test when cleaning up disconnected
215  * sessions if the segment can be removed.
216  */
217  }
218 
219  clib_spinlock_free (&sm->lockp);
220  pool_put (segment_managers, sm);
221 }
222 
223 static int
225  u32 fifo_segment_index)
226 {
227  application_t *app = application_get (sm->app_index);
228  u32 seg_size = 0;
229  u8 *seg_name;
230 
231  /* Send an API message to the external app, to map new segment */
232  ASSERT (app->cb_fns.add_segment_callback);
233 
234  segment_manager_get_segment_info (fifo_segment_index, &seg_name, &seg_size);
235  return app->cb_fns.add_segment_callback (app->api_client_index, seg_name,
236  seg_size);
237 }
238 
239 int
241  svm_fifo_t ** server_rx_fifo,
242  svm_fifo_t ** server_tx_fifo,
243  u32 * fifo_segment_index)
244 {
245  svm_fifo_segment_private_t *fifo_segment;
246  u32 fifo_size, sm_index;
247  u8 added_a_segment = 0;
248  int i;
249 
250  ASSERT (vec_len (sm->segment_indices));
251 
252  /* Make sure we don't have multiple threads trying to allocate segments
253  * at the same time. */
254  clib_spinlock_lock (&sm->lockp);
255 
256  /* Allocate svm fifos */
257 again:
258  for (i = 0; i < vec_len (sm->segment_indices); i++)
259  {
260  *fifo_segment_index = sm->segment_indices[i];
261  fifo_segment = svm_fifo_get_segment (*fifo_segment_index);
262 
263  /* FC: cleanup, make sure sm->properties->xxx_fifo_size always set */
264  fifo_size = sm->properties->rx_fifo_size;
265  fifo_size = (fifo_size == 0) ? default_fifo_size : fifo_size;
266  *server_rx_fifo =
267  svm_fifo_segment_alloc_fifo (fifo_segment, fifo_size,
269 
270  /* FC: cleanup, make sure sm->properties->xxx_fifo_size always set */
271  fifo_size = sm->properties->tx_fifo_size;
272  fifo_size = (fifo_size == 0) ? default_fifo_size : fifo_size;
273  *server_tx_fifo =
274  svm_fifo_segment_alloc_fifo (fifo_segment, fifo_size,
276 
277  if (*server_rx_fifo == 0)
278  {
279  /* This would be very odd, but handle it... */
280  if (*server_tx_fifo != 0)
281  {
282  svm_fifo_segment_free_fifo (fifo_segment, *server_tx_fifo,
284  *server_tx_fifo = 0;
285  }
286  continue;
287  }
288  if (*server_tx_fifo == 0)
289  {
290  if (*server_rx_fifo != 0)
291  {
292  svm_fifo_segment_free_fifo (fifo_segment, *server_rx_fifo,
294  *server_rx_fifo = 0;
295  }
296  continue;
297  }
298  break;
299  }
300 
301  /* See if we're supposed to create another segment */
302  if (*server_rx_fifo == 0)
303  {
304  if (sm->properties->add_segment)
305  {
306  if (added_a_segment)
307  {
308  clib_warning ("added a segment, still cant allocate a fifo");
309  clib_spinlock_unlock (&sm->lockp);
310  return SESSION_ERROR_NEW_SEG_NO_SPACE;
311  }
312 
314  {
315  clib_spinlock_unlock (&sm->lockp);
316  return VNET_API_ERROR_URI_FIFO_CREATE_FAILED;
317  }
318 
319  added_a_segment = 1;
320  goto again;
321  }
322  else
323  {
324  clib_warning ("No space to allocate fifos!");
325  clib_spinlock_unlock (&sm->lockp);
326  return SESSION_ERROR_NO_SPACE;
327  }
328  }
329 
330  /* Backpointers to segment manager */
331  sm_index = segment_manager_index (sm);
332  (*server_tx_fifo)->segment_manager = sm_index;
333  (*server_rx_fifo)->segment_manager = sm_index;
334 
335  clib_spinlock_unlock (&sm->lockp);
336 
337  if (added_a_segment)
338  return segment_manager_notify_app_seg_add (sm, *fifo_segment_index);
339 
340  return 0;
341 }
342 
343 void
344 segment_manager_dealloc_fifos (u32 svm_segment_index, svm_fifo_t * rx_fifo,
345  svm_fifo_t * tx_fifo)
346 {
347  segment_manager_t *sm;
348  svm_fifo_segment_private_t *fifo_segment;
349 
350  sm = segment_manager_get_if_valid (rx_fifo->segment_manager);
351 
352  /* It's possible to have no segment manager if the session was removed
353  * as result of a detach */
354  if (!sm)
355  return;
356 
357  fifo_segment = svm_fifo_get_segment (svm_segment_index);
358  svm_fifo_segment_free_fifo (fifo_segment, rx_fifo,
360  svm_fifo_segment_free_fifo (fifo_segment, tx_fifo,
362 
363  /* Remove segment only if it holds no fifos and not the first */
364  if (sm->segment_indices[0] != svm_segment_index
365  && !svm_fifo_segment_has_fifos (fifo_segment))
366  {
367  clib_spinlock_lock (&sm->lockp);
368  svm_fifo_segment_delete (fifo_segment);
369  vec_del1 (sm->segment_indices, svm_segment_index);
370  clib_spinlock_unlock (&sm->lockp);
371  }
372 }
373 
374 /**
375  * Allocates shm queue in the first segment
376  */
379 {
383  void *oldheap;
384 
385  ASSERT (sm->segment_indices != 0);
386 
387  segment = svm_fifo_get_segment (sm->segment_indices[0]);
388  sh = segment->ssvm.sh;
389 
390  oldheap = ssvm_push_heap (sh);
391  q =
392  unix_shared_memory_queue_init (queue_size, sizeof (session_fifo_event_t),
393  0 /* consumer pid */ , 0
394  /* signal when queue non-empty */ );
395  ssvm_pop_heap (oldheap);
396  return q;
397 }
398 
399 /**
400  * Frees shm queue allocated in the first segment
401  */
402 void
405 {
408  void *oldheap;
409 
410  ASSERT (sm->segment_indices != 0);
411 
412  segment = svm_fifo_get_segment (sm->segment_indices[0]);
413  sh = segment->ssvm.sh;
414 
415  oldheap = ssvm_push_heap (sh);
417  ssvm_pop_heap (oldheap);
418 }
419 
420 /*
421  * fd.io coding-style-patch-verification: ON
422  *
423  * Local Variables:
424  * eval: (c-set-style "gnu")
425  * End:
426  */
u64 ssvm_size
Definition: ssvm.h:77
static void segment_manager_alloc_process_private_segment(segment_manager_properties_t *props)
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:72
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:50
int segment_manager_alloc_session_fifos(segment_manager_t *sm, svm_fifo_t **server_rx_fifo, svm_fifo_t **server_tx_fifo, u32 *fifo_segment_index)
static segment_manager_t * segment_manager_get_if_valid(u32 index)
a
Definition: bitmap.h:516
struct _segment_manager_properties segment_manager_properties_t
u32 default_segment_size
void unix_shared_memory_queue_free(unix_shared_memory_queue_t *q)
int session_manager_add_first_segment(segment_manager_t *sm, u32 segment_size)
segment_manager_t * segment_managers
Pool of segment managers.
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
ssvm_shared_header_t * sh
Definition: ssvm.h:76
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
u32 private_segment_index
Process private segment index.
static void clib_spinlock_free(clib_spinlock_t *p)
Definition: lock.h:40
struct _stream_session_t stream_session_t
struct _svm_fifo svm_fifo_t
static int session_manager_add_segment_i(segment_manager_t *sm, u32 segment_size, u8 *segment_name)
void segment_manager_get_segment_info(u32 index, u8 **name, u32 *size)
#define always_inline
Definition: clib.h:84
static void * ssvm_push_heap(ssvm_shared_header_t *sh)
Definition: ssvm.h:117
unix_shared_memory_queue_t * segment_manager_alloc_queue(segment_manager_t *sm, u32 queue_size)
Allocates shm queue in the first segment.
static void ssvm_pop_heap(void *oldheap)
Definition: ssvm.h:125
void session_send_session_evt_to_thread(u64 session_handle, fifo_event_type_t evt_type, u32 thread_index)
Definition: session.c:973
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:33
int svm_fifo_segment_create_process_private(svm_fifo_segment_create_args_t *a)
Create an svm fifo segment in process-private memory.
static svm_fifo_t * svm_fifo_segment_get_fifo_list(svm_fifo_segment_private_t *fifo_segment)
u8 * segment_name
Segment name.
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:241
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:805
svm_fifo_segment_header_t * h
static u8 svm_fifo_segment_has_fifos(svm_fifo_segment_private_t *fifo_segment)
void segment_manager_dealloc_queue(segment_manager_t *sm, unix_shared_memory_queue_t *q)
Frees shm queue allocated in the first segment.
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
#define clib_warning(format, args...)
Definition: error.h:59
struct _application application_t
static int segment_manager_notify_app_seg_add(segment_manager_t *sm, u32 fifo_segment_index)
static svm_fifo_segment_private_t * svm_fifo_get_segment(u32 segment_index)
static u32 segment_manager_index(segment_manager_t *sm)
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
unix_shared_memory_queue_t * unix_shared_memory_queue_init(int nels, int elsize, int consumer_pid, int signal_when_queue_non_empty)
u64 size
Definition: vhost-user.h:75
void svm_fifo_segment_free_fifo(svm_fifo_segment_private_t *s, svm_fifo_t *f, svm_fifo_segment_freelist_t list_index)
int svm_fifo_segment_create(svm_fifo_segment_create_args_t *a)
(master) create an svm fifo segment
void segment_manager_del(segment_manager_t *sm)
Removes segment manager.
static u64 stream_session_handle(stream_session_t *s)
Definition: session.h:299
int segment_manager_init(segment_manager_t *sm, segment_manager_properties_t *properties, u32 first_seg_size)
Initializes segment manager based on options provided.
void segment_manager_dealloc_fifos(u32 svm_segment_index, svm_fifo_t *rx_fifo, svm_fifo_t *tx_fifo)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
u32 segment_name_counter
Counter used to build segment names.
application_t * application_get(u32 index)
Definition: application.c:189
struct _segment_manager segment_manager_t
int session_manager_add_segment(segment_manager_t *sm)
u32 default_fifo_size
Default fifo and segment size.
void svm_fifo_segment_delete(svm_fifo_segment_private_t *s)
struct _unix_shared_memory_queue unix_shared_memory_queue_t
static stream_session_t * stream_session_get(u32 si, u32 thread_index)
Definition: session.h:281
svm_fifo_t * svm_fifo_segment_alloc_fifo(svm_fifo_segment_private_t *s, u32 data_size_in_bytes, svm_fifo_segment_freelist_t list_index)