FD.io VPP  v19.08.2-294-g37e99c22d
Vector Packet Processing
ssvm.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-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 #include <svm/ssvm.h>
16 #include <svm/svm_common.h>
17 
18 typedef int (*init_fn) (ssvm_private_t *);
19 typedef void (*delete_fn) (ssvm_private_t *);
20 
27 
28 int
30 {
31  int ssvm_fd;
32 #if USE_DLMALLOC == 0
34 #endif
35  clib_mem_vm_map_t mapa = { 0 };
36  u8 junk = 0, *ssvm_filename;
38  uword page_size, requested_va = 0;
39  void *oldheap;
40 
41  if (ssvm->ssvm_size == 0)
42  return SSVM_API_ERROR_NO_SIZE;
43 
44  if (CLIB_DEBUG > 1)
45  clib_warning ("[%d] creating segment '%s'", getpid (), ssvm->name);
46 
48  ssvm_filename = format (0, "/dev/shm/%s%c", ssvm->name, 0);
49  unlink ((char *) ssvm_filename);
50  vec_free (ssvm_filename);
51 
52  ssvm_fd = shm_open ((char *) ssvm->name, O_RDWR | O_CREAT | O_EXCL, 0777);
53  if (ssvm_fd < 0)
54  {
55  clib_unix_warning ("create segment '%s'", ssvm->name);
56  return SSVM_API_ERROR_CREATE_FAILURE;
57  }
58 
59  if (fchmod (ssvm_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0)
60  clib_unix_warning ("ssvm segment chmod");
61  if (svm_get_root_rp ())
62  {
63  /* TODO: is this really needed? */
65  if (fchown (ssvm_fd, smr->uid, smr->gid) < 0)
66  clib_unix_warning ("ssvm segment chown");
67  }
68 
69  if (lseek (ssvm_fd, ssvm->ssvm_size, SEEK_SET) < 0)
70  {
71  clib_unix_warning ("lseek");
72  close (ssvm_fd);
73  return SSVM_API_ERROR_SET_SIZE;
74  }
75 
76  if (write (ssvm_fd, &junk, 1) != 1)
77  {
78  clib_unix_warning ("set ssvm size");
79  close (ssvm_fd);
80  return SSVM_API_ERROR_SET_SIZE;
81  }
82 
83  page_size = clib_mem_get_fd_page_size (ssvm_fd);
84  if (ssvm->requested_va)
85  {
86  requested_va = ssvm->requested_va;
87  clib_mem_vm_randomize_va (&requested_va, min_log2 (page_size));
88  }
89 
90  mapa.requested_va = requested_va;
91  mapa.size = ssvm->ssvm_size;
92  mapa.fd = ssvm_fd;
93  if (clib_mem_vm_ext_map (&mapa))
94  {
95  clib_unix_warning ("mmap");
96  close (ssvm_fd);
97  return SSVM_API_ERROR_MMAP;
98  }
99  close (ssvm_fd);
100 
101  sh = mapa.addr;
102  sh->master_pid = ssvm->my_pid;
103  sh->ssvm_size = ssvm->ssvm_size;
104  sh->ssvm_va = pointer_to_uword (sh);
105  sh->type = SSVM_SEGMENT_SHM;
106 #if USE_DLMALLOC == 0
107  sh->heap = mheap_alloc_with_flags (((u8 *) sh) + page_size,
108  ssvm->ssvm_size - page_size, mh_flags);
109 #else
110  sh->heap = create_mspace_with_base (((u8 *) sh) + page_size,
111  ssvm->ssvm_size - page_size,
112  1 /* locked */ );
113  mspace_disable_expand (sh->heap);
114 #endif
115 
116  oldheap = ssvm_push_heap (sh);
117  sh->name = format (0, "%s", ssvm->name, 0);
118  ssvm_pop_heap (oldheap);
119 
120  ssvm->sh = sh;
121  ssvm->my_pid = getpid ();
122  ssvm->i_am_master = 1;
123 
124  /* The application has to set set sh->ready... */
125  return 0;
126 }
127 
128 int
130 {
131  struct stat stat;
132  int ssvm_fd = -1;
134 
136  ssvm->i_am_master = 0;
137 
138  while (ssvm->attach_timeout-- > 0)
139  {
140  if (ssvm_fd < 0)
141  ssvm_fd = shm_open ((char *) ssvm->name, O_RDWR, 0777);
142  if (ssvm_fd < 0)
143  {
144  sleep (1);
145  continue;
146  }
147  if (fstat (ssvm_fd, &stat) < 0)
148  {
149  sleep (1);
150  continue;
151  }
152 
153  if (stat.st_size > 0)
154  goto map_it;
155  }
156  clib_warning ("slave timeout");
157  return SSVM_API_ERROR_SLAVE_TIMEOUT;
158 
159 map_it:
160  sh = (void *) mmap (0, MMAP_PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
161  ssvm_fd, 0);
162  if (sh == MAP_FAILED)
163  {
164  clib_unix_warning ("slave research mmap");
165  close (ssvm_fd);
166  return SSVM_API_ERROR_MMAP;
167  }
168 
169  while (ssvm->attach_timeout-- > 0)
170  {
171  if (sh->ready)
172  goto re_map_it;
173  }
174  close (ssvm_fd);
175  munmap (sh, MMAP_PAGESIZE);
176  clib_warning ("slave timeout 2");
177  return SSVM_API_ERROR_SLAVE_TIMEOUT;
178 
179 re_map_it:
180  ssvm->requested_va = sh->ssvm_va;
181  ssvm->ssvm_size = sh->ssvm_size;
182  munmap (sh, MMAP_PAGESIZE);
183 
184  sh = ssvm->sh = (void *) mmap ((void *) ssvm->requested_va, ssvm->ssvm_size,
185  PROT_READ | PROT_WRITE,
186  MAP_SHARED | MAP_FIXED, ssvm_fd, 0);
187 
188  if (sh == MAP_FAILED)
189  {
190  clib_unix_warning ("slave final mmap");
191  close (ssvm_fd);
192  return SSVM_API_ERROR_MMAP;
193  }
194  sh->slave_pid = getpid ();
195  return 0;
196 }
197 
198 void
200 {
201  u8 *fn;
202 
203  fn = format (0, "/dev/shm/%s%c", ssvm->name, 0);
204 
205  if (CLIB_DEBUG > 1)
206  clib_warning ("[%d] unlinking ssvm (%s) backing file '%s'", getpid (),
207  ssvm->name, fn);
208 
209  /* Throw away the backing file */
210  if (unlink ((char *) fn) < 0)
211  clib_unix_warning ("unlink segment '%s'", ssvm->name);
212 
213  vec_free (fn);
214  vec_free (ssvm->name);
215 
216  munmap ((void *) ssvm->sh, ssvm->ssvm_size);
217 }
218 
219 /**
220  * Initialize memfd segment master
221  */
222 int
224 {
225  uword page_size;
227  void *oldheap;
228  clib_mem_vm_alloc_t alloc = { 0 };
229  clib_error_t *err;
230 
231  if (memfd->ssvm_size == 0)
232  return SSVM_API_ERROR_NO_SIZE;
233 
235 
236  alloc.name = (char *) memfd->name;
237  alloc.size = memfd->ssvm_size;
238  alloc.flags = CLIB_MEM_VM_F_SHARED;
239  alloc.requested_va = memfd->requested_va;
240  if ((err = clib_mem_vm_ext_alloc (&alloc)))
241  {
242  clib_error_report (err);
243  return SSVM_API_ERROR_CREATE_FAILURE;
244  }
245 
246  memfd->fd = alloc.fd;
247  memfd->sh = (ssvm_shared_header_t *) alloc.addr;
248  memfd->my_pid = getpid ();
249  memfd->i_am_master = 1;
250 
251  page_size = 1ull << alloc.log2_page_size;
252  sh = memfd->sh;
253  sh->master_pid = memfd->my_pid;
254  sh->ssvm_size = memfd->ssvm_size;
255  sh->ssvm_va = pointer_to_uword (sh);
256  sh->type = SSVM_SEGMENT_MEMFD;
257 
258 #if USE_DLMALLOC == 0
260 
261  sh->heap = mheap_alloc_with_flags (((u8 *) sh) + page_size,
262  memfd->ssvm_size - page_size, flags);
263 #else
264  sh->heap = create_mspace_with_base (((u8 *) sh) + page_size,
265  memfd->ssvm_size - page_size,
266  1 /* locked */ );
267  mspace_disable_expand (sh->heap);
268 #endif
269  oldheap = ssvm_push_heap (sh);
270  sh->name = format (0, "%s", memfd->name, 0);
271  ssvm_pop_heap (oldheap);
272 
273  /* The application has to set set sh->ready... */
274  return 0;
275 }
276 
277 /**
278  * Initialize memfd segment slave
279  *
280  * Subtly different than svm_slave_init. The caller needs to acquire
281  * a usable file descriptor for the memfd segment e.g. via
282  * vppinfra/socket.c:default_socket_recvmsg
283  */
284 int
286 {
287  clib_mem_vm_map_t mapa = { 0 };
289  uword page_size;
290 
291  memfd->i_am_master = 0;
292 
293  page_size = clib_mem_get_fd_page_size (memfd->fd);
294  if (!page_size)
295  {
296  clib_unix_warning ("page size unknown");
297  return SSVM_API_ERROR_MMAP;
298  }
299 
300  /*
301  * Map the segment once, to look at the shared header
302  */
303  mapa.fd = memfd->fd;
304  mapa.size = page_size;
305 
306  if (clib_mem_vm_ext_map (&mapa))
307  {
308  clib_unix_warning ("slave research mmap (fd %d)", mapa.fd);
309  close (memfd->fd);
310  return SSVM_API_ERROR_MMAP;
311  }
312 
313  sh = mapa.addr;
314  memfd->requested_va = sh->ssvm_va;
315  memfd->ssvm_size = sh->ssvm_size;
316  clib_mem_vm_free (sh, page_size);
317 
318  /*
319  * Remap the segment at the 'right' address
320  */
321  mapa.requested_va = memfd->requested_va;
322  mapa.size = memfd->ssvm_size;
323  if (clib_mem_vm_ext_map (&mapa))
324  {
325  clib_unix_warning ("slave final mmap");
326  close (memfd->fd);
327  return SSVM_API_ERROR_MMAP;
328  }
329 
330  sh = mapa.addr;
331  sh->slave_pid = getpid ();
332  memfd->sh = sh;
333  return 0;
334 }
335 
336 void
338 {
339  vec_free (memfd->name);
340  clib_mem_vm_free (memfd->sh, memfd->ssvm_size);
341  close (memfd->fd);
342 }
343 
344 /**
345  * Initialize segment in a private heap
346  */
347 int
349 {
351  u32 pagesize = clib_mem_get_page_size ();
352  u32 rnd_size = 0;
353  u8 *heap;
354 
355  rnd_size = clib_max (ssvm->ssvm_size + (pagesize - 1), ssvm->ssvm_size);
356  rnd_size &= ~(pagesize - 1);
357 
358 #if USE_DLMALLOC == 0
359  {
361 
362  heap = mheap_alloc (0, rnd_size);
363  if (heap == 0)
364  {
365  clib_unix_warning ("mheap alloc");
366  return -1;
367  }
368  heap_header = mheap_header (heap);
369  heap_header->flags |= MHEAP_FLAG_THREAD_SAFE;
370  }
371 #else
372  heap = create_mspace (rnd_size, 1 /* locked */ );
373  if (heap == 0)
374  {
375  clib_unix_warning ("mheap alloc");
376  return -1;
377  }
378 
379  mspace_disable_expand (heap);
380 
381  /* Find actual size because mspace size is rounded up by dlmalloc */
382  struct dlmallinfo dlminfo;
383  dlminfo = mspace_mallinfo (heap);
384  rnd_size = dlminfo.fordblks;
385 #endif
386 
387  ssvm->ssvm_size = rnd_size;
388  ssvm->i_am_master = 1;
389  ssvm->my_pid = getpid ();
390  ssvm->requested_va = ~0;
391 
392  /* Allocate a [sic] shared memory header, in process memory... */
393  sh = clib_mem_alloc_aligned (sizeof (*sh), CLIB_CACHE_LINE_BYTES);
394  ssvm->sh = sh;
395 
396  clib_memset (sh, 0, sizeof (*sh));
397  sh->heap = heap;
398  sh->ssvm_va = pointer_to_uword (heap);
400  sh->name = ssvm->name;
401 
402  return 0;
403 }
404 
405 int
407 {
408  clib_warning ("BUG: this should not be called!");
409  return -1;
410 }
411 
412 void
414 {
415  vec_free (ssvm->name);
416 #if USE_DLMALLOC == 0
417  mheap_free (ssvm->sh->heap);
418 #else
419  destroy_mspace (ssvm->sh->heap);
420 #endif
421  clib_mem_free (ssvm->sh);
422 }
423 
424 int
426 {
427  return (master_init_fns[type]) (ssvm);
428 }
429 
430 int
432 {
433  return (slave_init_fns[type]) (ssvm);
434 }
435 
436 void
438 {
439  delete_fns[ssvm->sh->type] (ssvm);
440 }
441 
443 ssvm_type (const ssvm_private_t * ssvm)
444 {
445  return ssvm->sh->type;
446 }
447 
448 u8 *
449 ssvm_name (const ssvm_private_t * ssvm)
450 {
451  return ssvm->sh->name;
452 }
453 
454 /*
455  * fd.io coding-style-patch-verification: ON
456  *
457  * Local Variables:
458  * eval: (c-set-style "gnu")
459  * End:
460  */
u64 ssvm_size
Definition: ssvm.h:85
svm_region_t * svm_get_root_rp(void)
Definition: svm.c:54
u32 flags
Definition: vhost_user.h:141
static init_fn slave_init_fns[SSVM_N_SEGMENT_TYPES]
Definition: ssvm.c:23
static init_fn master_init_fns[SSVM_N_SEGMENT_TYPES]
Definition: ssvm.c:21
uword requested_va
Definition: ssvm.h:88
#define vec_c_string_is_terminated(V)
Test whether a vector is a NULL terminated c-string.
Definition: vec.h:1010
volatile u32 ready
Definition: ssvm.h:77
void * mheap_alloc(void *memory, uword size)
Definition: mheap.c:963
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
ssvm_segment_type_t type
Definition: ssvm.h:79
void * addr
Pointer to allocated memory, set on successful allocation.
Definition: mem.h:413
uword requested_va
Request fixed position mapping.
Definition: mem.h:417
void(* delete_fn)(ssvm_private_t *)
Definition: ssvm.c:19
static mheap_t * mheap_header(u8 *v)
int ssvm_slave_init_shm(ssvm_private_t *ssvm)
Definition: ssvm.c:129
ssvm_shared_header_t * sh
Definition: ssvm.h:84
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
DLMALLOC_EXPORT struct dlmallinfo mspace_mallinfo(mspace msp)
#define MHEAP_FLAG_THREAD_SAFE
int ssvm_master_init_shm(ssvm_private_t *ssvm)
Definition: ssvm.c:29
unsigned char u8
Definition: types.h:56
static uword min_log2(uword x)
Definition: clib.h:145
void ssvm_delete(ssvm_private_t *ssvm)
Definition: ssvm.c:437
int ssvm_slave_init_private(ssvm_private_t *ssvm)
Definition: ssvm.c:406
DLMALLOC_EXPORT mspace create_mspace_with_base(void *base, size_t capacity, int locked)
u8 * ssvm_name(const ssvm_private_t *ssvm)
Definition: ssvm.c:449
enum ssvm_segment_type_ ssvm_segment_type_t
clib_error_t * clib_mem_vm_ext_map(clib_mem_vm_map_t *a)
Definition: mem.c:386
clib_error_t * clib_mem_vm_ext_alloc(clib_mem_vm_alloc_t *a)
Definition: mem.c:193
uword requested_va
Request fixed position mapping.
Definition: mem.h:433
int(* init_fn)(ssvm_private_t *)
Definition: ssvm.c:18
#define MHEAP_FLAG_DISABLE_VM
int ssvm_master_init_memfd(ssvm_private_t *memfd)
Initialize memfd segment master.
Definition: ssvm.c:223
char * name
Name for memory allocation, set by caller.
Definition: mem.h:410
static void * ssvm_push_heap(ssvm_shared_header_t *sh)
Definition: ssvm.h:143
uword size
Allocation size, set by caller.
Definition: mem.h:411
unsigned int u32
Definition: types.h:88
int attach_timeout
shm segments attach timeout (sec)
Definition: ssvm.h:94
#define mheap_free(v)
Definition: mheap.h:65
int ssvm_master_init(ssvm_private_t *ssvm, ssvm_segment_type_t type)
Definition: ssvm.c:425
static void ssvm_pop_heap(void *oldheap)
Definition: ssvm.h:151
vl_api_fib_path_type_t type
Definition: fib_types.api:123
#define CLIB_MEM_VM_F_SHARED
Definition: mem.h:393
void * data_base
Definition: svm_common.h:45
int fd
File descriptor, set on successful allocation if CLIB_MEM_VM_F_SHARED is set.
Definition: mem.h:414
DLMALLOC_EXPORT void mspace_disable_expand(mspace msp)
uword clib_mem_get_page_size(void)
Definition: mem.c:51
u64 clib_mem_get_fd_page_size(int fd)
Definition: mem.c:91
DLMALLOC_EXPORT mspace create_mspace(size_t capacity, int locked)
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
#define clib_warning(format, args...)
Definition: error.h:59
int ssvm_slave_init(ssvm_private_t *ssvm, ssvm_segment_type_t type)
Definition: ssvm.c:431
u32 my_pid
Definition: ssvm.h:86
u32 flags
vm allocation flags: CLIB_MEM_VM_F_SHARED: request shared memory, file descriptor will be provided ...
Definition: mem.h:399
int fd
memfd segments
Definition: ssvm.h:93
void * mheap_alloc_with_flags(void *memory, uword memory_size, uword flags)
Definition: mheap.c:885
#define ASSERT(truth)
uword size
Map size.
Definition: mem.h:431
static void clib_mem_free(void *p)
Definition: mem.h:226
#define clib_error_report(e)
Definition: error.h:113
static heap_header_t * heap_header(void *v)
Definition: heap.h:161
static uword pointer_to_uword(const void *p)
Definition: types.h:131
#define clib_max(x, y)
Definition: clib.h:295
u8 * name
Definition: ssvm.h:87
#define MMAP_PAGESIZE
Definition: ssvm.h:43
static void clib_mem_vm_free(void *addr, uword size)
Definition: mem.h:356
uword ssvm_size
Definition: ssvm.h:70
u64 uword
Definition: types.h:112
static delete_fn delete_fns[SSVM_N_SEGMENT_TYPES]
Definition: ssvm.c:25
#define clib_unix_warning(format, args...)
Definition: error.h:68
void ssvm_delete_memfd(ssvm_private_t *memfd)
Definition: ssvm.c:337
void clib_mem_vm_randomize_va(uword *requested_va, u32 log2_page_size)
Definition: mem.c:106
int ssvm_master_init_private(ssvm_private_t *ssvm)
Initialize segment in a private heap.
Definition: ssvm.c:348
DLMALLOC_EXPORT size_t destroy_mspace(mspace msp)
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:161
int fd
File descriptor to be mapped.
Definition: mem.h:432
void ssvm_delete_private(ssvm_private_t *ssvm)
Definition: ssvm.c:413
void ssvm_delete_shm(ssvm_private_t *ssvm)
Definition: ssvm.c:199
int log2_page_size
Definition: mem.h:415
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
Private segments.
Definition: ssvm.h:53
int i_am_master
Definition: ssvm.h:89
int ssvm_slave_init_memfd(ssvm_private_t *memfd)
Initialize memfd segment slave.
Definition: ssvm.c:285
void * addr
Pointer to mapped memory, if successful.
Definition: mem.h:434
ssvm_segment_type_t ssvm_type(const ssvm_private_t *ssvm)
Definition: ssvm.c:443