FD.io VPP  v17.07.01-10-g3be13f0
Vector Packet Processing
svm_fifo_segment.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 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 <svm/svm_fifo_segment.h>
17 
19 
20 static void
23 {
24  u32 rx_fifo_size, tx_fifo_size;
25  svm_fifo_t *f;
26  u8 *rx_fifo_space, *tx_fifo_space;
27  int i;
28 
29  /* Parameter check */
30  if (a->rx_fifo_size == 0 || a->tx_fifo_size == 0
31  || a->preallocated_fifo_pairs == 0)
32  return;
33 
34  /* Calculate space requirements */
35  rx_fifo_size = (sizeof (*f) + a->rx_fifo_size) * a->preallocated_fifo_pairs;
36  tx_fifo_size = (sizeof (*f) + a->tx_fifo_size) * a->preallocated_fifo_pairs;
37 
38  /* Allocate rx fifo space. May fail. */
39  rx_fifo_space = clib_mem_alloc_aligned_at_offset
40  (rx_fifo_size, CLIB_CACHE_LINE_BYTES, 0 /* align_offset */ ,
41  0 /* os_out_of_memory */ );
42 
43  /* Same for TX */
44  tx_fifo_space = clib_mem_alloc_aligned_at_offset
45  (tx_fifo_size, CLIB_CACHE_LINE_BYTES, 0 /* align_offset */ ,
46  0 /* os_out_of_memory */ );
47 
48  /* Make sure it worked. Clean up if it didn't... */
49  if (rx_fifo_space == 0 || tx_fifo_space == 0)
50  {
51  if (rx_fifo_space)
52  clib_mem_free (rx_fifo_space);
53  else
54  clib_warning ("rx fifo preallocation failure: size %d npairs %d",
56 
57  if (tx_fifo_space)
58  clib_mem_free (tx_fifo_space);
59  else
60  clib_warning ("tx fifo preallocation failure: size %d nfifos %d",
62  return;
63  }
64 
65  /* Carve rx fifo space */
66  f = (svm_fifo_t *) rx_fifo_space;
67  for (i = 0; i < a->preallocated_fifo_pairs; i++)
68  {
69  f->next = fsh->free_fifos[FIFO_SEGMENT_RX_FREELIST];
71  rx_fifo_space += sizeof (*f) + a->rx_fifo_size;
72  f = (svm_fifo_t *) rx_fifo_space;
73  }
74  /* Carve tx fifo space */
75  f = (svm_fifo_t *) tx_fifo_space;
76  for (i = 0; i < a->preallocated_fifo_pairs; i++)
77  {
78  f->next = fsh->free_fifos[FIFO_SEGMENT_TX_FREELIST];
80  tx_fifo_space += sizeof (*f) + a->tx_fifo_size;
81  f = (svm_fifo_t *) tx_fifo_space;
82  }
83 }
84 
85 /** (master) create an svm fifo segment */
86 int
88 {
89  int rv;
94  void *oldheap;
95 
96  /* Allocate a fresh segment */
97  pool_get (sm->segments, s);
98  memset (s, 0, sizeof (*s));
99 
100  s->ssvm.ssvm_size = a->segment_size;
101  s->ssvm.i_am_master = 1;
102  s->ssvm.my_pid = getpid ();
103  s->ssvm.name = (u8 *) a->segment_name;
104  s->ssvm.requested_va = sm->next_baseva;
105 
106  rv = ssvm_master_init (&s->ssvm, s - sm->segments);
107 
108  if (rv)
109  {
110  _vec_len (s) = vec_len (s) - 1;
111  return (rv);
112  }
113 
114  /* Note; requested_va updated due to seg base addr randomization */
116 
117  sh = s->ssvm.sh;
118  oldheap = ssvm_push_heap (sh);
119 
120  /* Set up svm_fifo_segment shared header */
121  fsh = clib_mem_alloc (sizeof (*fsh));
122  memset (fsh, 0, sizeof (*fsh));
123  sh->opaque[0] = fsh;
124  s->h = fsh;
125  fsh->segment_name = format (0, "%s%c", a->segment_name, 0);
126 
127  preallocate_fifo_pairs (fsh, a);
128 
129  ssvm_pop_heap (oldheap);
130 
131  sh->ready = 1;
132  a->new_segment_index = s - sm->segments;
133  return (0);
134 }
135 
136 /** Create an svm fifo segment in process-private memory */
137 int
139 {
144 
145  /* Allocate a fresh segment */
146  pool_get (sm->segments, s);
147  memset (s, 0, sizeof (*s));
148 
149  s->ssvm.ssvm_size = ~0;
150  s->ssvm.i_am_master = 1;
151  s->ssvm.my_pid = getpid ();
152  s->ssvm.name = (u8 *) a->segment_name;
153  s->ssvm.requested_va = ~0;
154 
155  /* Allocate a [sic] shared memory header, in process memory... */
156  sh = clib_mem_alloc_aligned (sizeof (*sh), CLIB_CACHE_LINE_BYTES);
157  s->ssvm.sh = sh;
158 
159  memset (sh, 0, sizeof (*sh));
160  sh->heap = clib_mem_get_heap ();
161 
162  /* Set up svm_fifo_segment shared header */
163  fsh = clib_mem_alloc (sizeof (*fsh));
164  memset (fsh, 0, sizeof (*fsh));
165  sh->opaque[0] = fsh;
166  s->h = fsh;
167  fsh->segment_name = format (0, "%s%c", a->segment_name, 0);
168 
169  preallocate_fifo_pairs (fsh, a);
170 
171  sh->ready = 1;
172  a->new_segment_index = s - sm->segments;
173  return (0);
174 }
175 
176 /** (slave) attach to an svm fifo segment */
177 int
179 {
180  int rv;
185 
186  /* Allocate a fresh segment */
187  pool_get (sm->segments, s);
188  memset (s, 0, sizeof (*s));
189 
190  s->ssvm.ssvm_size = a->segment_size;
191  s->ssvm.my_pid = getpid ();
192  s->ssvm.name = (u8 *) a->segment_name;
193  s->ssvm.requested_va = sm->next_baseva;
194 
195  rv = ssvm_slave_init (&s->ssvm, sm->timeout_in_seconds);
196 
197  if (rv)
198  {
199  _vec_len (s) = vec_len (s) - 1;
200  return (rv);
201  }
202 
203  /* Fish the segment header */
204  sh = s->ssvm.sh;
205  fsh = (svm_fifo_segment_header_t *) sh->opaque[0];
206  s->h = fsh;
207 
208  a->new_segment_index = s - sm->segments;
209  return (0);
210 }
211 
212 void
214 {
216  ssvm_delete (&s->ssvm);
217  pool_put (sm->segments, s);
218 }
219 
220 svm_fifo_t *
222  u32 data_size_in_bytes,
223  svm_fifo_segment_freelist_t list_index)
224 {
227  svm_fifo_t *f;
228  void *oldheap;
229 
230  sh = s->ssvm.sh;
231  fsh = (svm_fifo_segment_header_t *) sh->opaque[0];
232 
233  ssvm_lock (sh, 1, 0);
234  oldheap = ssvm_push_heap (sh);
235 
236  switch (list_index)
237  {
240  f = fsh->free_fifos[list_index];
241  if (f)
242  {
243  fsh->free_fifos[list_index] = f->next;
244  /* (re)initialize the fifo, as in svm_fifo_create */
245  memset (f, 0, sizeof (*f));
246  f->nitems = data_size_in_bytes;
247  f->ooos_list_head = OOO_SEGMENT_INVALID_INDEX;
248  goto found;
249  }
250  /* FALLTHROUGH */
252  break;
253 
254  default:
255  clib_warning ("ignore bogus freelist %d", list_index);
256  break;
257  }
258 
259  /* Note: this can fail, in which case: create another segment */
260  f = svm_fifo_create (data_size_in_bytes);
261  if (PREDICT_FALSE (f == 0))
262  {
263  ssvm_pop_heap (oldheap);
264  ssvm_unlock (sh);
265  return (0);
266  }
267 
268 found:
269  /* If rx_freelist add to active fifos list. When cleaning up segment,
270  * we need a list of active sessions that should be disconnected. Since
271  * both rx and tx fifos keep pointers to the session, it's enough to track
272  * only one. */
273  if (list_index == FIFO_SEGMENT_RX_FREELIST)
274  {
275  if (fsh->fifos)
276  {
277  fsh->fifos->prev = f;
278  f->next = fsh->fifos;
279  }
280  fsh->fifos = f;
281  }
282 
283  ssvm_pop_heap (oldheap);
284  ssvm_unlock (sh);
285  return (f);
286 }
287 
288 void
290  svm_fifo_segment_freelist_t list_index)
291 {
294  void *oldheap;
295 
296  sh = s->ssvm.sh;
297  fsh = (svm_fifo_segment_header_t *) sh->opaque[0];
298 
299  ssvm_lock (sh, 1, 0);
300  oldheap = ssvm_push_heap (sh);
301 
302  switch (list_index)
303  {
305  /* Remove from active list */
306  if (f->prev)
307  f->prev->next = f->next;
308  else
309  fsh->fifos = f->next;
310  if (f->next)
311  f->next->prev = f->prev;
312  /* Fall through: we add only rx fifos to active pool */
314  /* Add to free list */
315  f->next = fsh->free_fifos[list_index];
316  f->prev = 0;
317  fsh->free_fifos[list_index] = f;
318  break;
320  break;
321 
322  default:
323  clib_warning ("ignore bogus freelist %d", list_index);
324  break;
325  }
326 
327  ssvm_pop_heap (oldheap);
328  ssvm_unlock (sh);
329 }
330 
331 void
332 svm_fifo_segment_init (u64 baseva, u32 timeout_in_seconds)
333 {
335 
336  sm->next_baseva = baseva;
337  sm->timeout_in_seconds = timeout_in_seconds;
338 }
339 
340 u32
342 {
343  return s - svm_fifo_segment_main.segments;
344 }
345 
346 /*
347  * fd.io coding-style-patch-verification: ON
348  *
349  * Local Variables:
350  * eval: (c-set-style "gnu")
351  * End:
352  */
u64 ssvm_size
Definition: ssvm.h:77
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
uword requested_va
Definition: ssvm.h:81
static void * clib_mem_alloc_aligned_at_offset(uword size, uword align, uword align_offset, int os_out_of_memory_on_failure)
Definition: mem.h:72
int ssvm_master_init(ssvm_private_t *ssvm, u32 master_index)
Definition: ssvm.c:18
a
Definition: bitmap.h:516
volatile u32 ready
Definition: ssvm.h:68
svm_fifo_segment_freelist_t
void * opaque[SSVM_N_OPAQUE]
Definition: ssvm.h:65
ssvm_shared_header_t * sh
Definition: ssvm.h:76
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
void ssvm_delete(ssvm_private_t *ssvm)
Definition: ssvm.c:173
svm_fifo_segment_main_t svm_fifo_segment_main
struct _svm_fifo svm_fifo_t
static void * ssvm_push_heap(ssvm_shared_header_t *sh)
Definition: ssvm.h:117
unsigned long u64
Definition: types.h:89
static void ssvm_pop_heap(void *oldheap)
Definition: ssvm.h:125
int svm_fifo_segment_create_process_private(svm_fifo_segment_create_args_t *a)
Create an svm fifo segment in process-private memory.
static void ssvm_unlock(ssvm_shared_header_t *h)
Definition: ssvm.h:105
u8 * segment_name
Segment name.
svm_fifo_t * fifos
Linked list of active RX fifos.
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:241
int ssvm_slave_init(ssvm_private_t *ssvm, int timeout_in_seconds)
Definition: ssvm.c:104
void svm_fifo_segment_init(u64 baseva, u32 timeout_in_seconds)
#define PREDICT_FALSE(x)
Definition: clib.h:97
svm_fifo_segment_header_t * h
u32 svm_fifo_segment_index(svm_fifo_segment_private_t *s)
#define clib_warning(format, args...)
Definition: error.h:59
u32 my_pid
Definition: ssvm.h:78
#define OOO_SEGMENT_INVALID_INDEX
Definition: svm_fifo.h:39
static void * clib_mem_get_heap(void)
Definition: mem.h:217
unsigned int u32
Definition: types.h:88
static void clib_mem_free(void *p)
Definition: mem.h:176
static void * clib_mem_alloc(uword size)
Definition: mem.h:109
void svm_fifo_segment_free_fifo(svm_fifo_segment_private_t *s, svm_fifo_t *f, svm_fifo_segment_freelist_t list_index)
u8 * name
Definition: ssvm.h:80
int svm_fifo_segment_create(svm_fifo_segment_create_args_t *a)
(master) create an svm fifo segment
svm_fifo_segment_private_t * segments
pool of segments
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
svm_fifo_t * free_fifos[FIFO_SEGMENT_N_FREELISTS]
Free lists.
unsigned char u8
Definition: types.h:56
static void preallocate_fifo_pairs(svm_fifo_segment_header_t *fsh, svm_fifo_segment_create_args_t *a)
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:117
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
int svm_fifo_segment_attach(svm_fifo_segment_create_args_t *a)
(slave) attach to an svm fifo segment
int i_am_master
Definition: ssvm.h:82
static void ssvm_lock(ssvm_shared_header_t *h, u32 my_pid, u32 tag)
Definition: ssvm.h:88
void svm_fifo_segment_delete(svm_fifo_segment_private_t *s)
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)
svm_fifo_t * svm_fifo_create(u32 data_size_in_bytes)
create an svm fifo, in the current heap.
Definition: svm_fifo.c:107