blob: 04e0efa3d622d76f0944135b34b1fe9ccbe30ac8 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 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 */
Florin Coras4d9b9d82018-01-14 12:25:50 -080015#include <svm/ssvm.h>
16#include <svm/svm_common.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070017
Florin Corasb384b542018-01-15 01:08:33 -080018typedef int (*init_fn) (ssvm_private_t *);
19typedef void (*delete_fn) (ssvm_private_t *);
20
21static init_fn master_init_fns[SSVM_N_SEGMENT_TYPES] =
Florin Corasa332c462018-01-31 06:52:17 -080022 { ssvm_master_init_shm, ssvm_master_init_memfd, ssvm_master_init_private };
Florin Corasb384b542018-01-15 01:08:33 -080023static init_fn slave_init_fns[SSVM_N_SEGMENT_TYPES] =
Florin Corasa332c462018-01-31 06:52:17 -080024 { ssvm_slave_init_shm, ssvm_slave_init_memfd, ssvm_slave_init_private };
Florin Corasb384b542018-01-15 01:08:33 -080025static delete_fn delete_fns[SSVM_N_SEGMENT_TYPES] =
Florin Corasa332c462018-01-31 06:52:17 -080026 { ssvm_delete_shm, ssvm_delete_memfd, ssvm_delete_private };
Florin Corasb384b542018-01-15 01:08:33 -080027
Dave Barach8a7fb0c2016-07-08 14:44:23 -040028int
Florin Corasb384b542018-01-15 01:08:33 -080029ssvm_master_init_shm (ssvm_private_t * ssvm)
Ed Warnickecb9cada2015-12-08 15:45:58 -070030{
Florin Corasb384b542018-01-15 01:08:33 -080031 int ssvm_fd, mh_flags = MHEAP_FLAG_DISABLE_VM | MHEAP_FLAG_THREAD_SAFE;
Dave Wallace19296112017-08-31 15:54:11 -040032 svm_main_region_t *smr = svm_get_root_rp ()->data_base;
Florin Corasb384b542018-01-15 01:08:33 -080033 clib_mem_vm_map_t mapa = { 0 };
34 u8 junk = 0, *ssvm_filename;
Dave Barach8a7fb0c2016-07-08 14:44:23 -040035 ssvm_shared_header_t *sh;
Florin Corasf8f516a2018-02-08 15:10:09 -080036 uword page_size, requested_va = 0;
Dave Barach8a7fb0c2016-07-08 14:44:23 -040037 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -070038
39 if (ssvm->ssvm_size == 0)
40 return SSVM_API_ERROR_NO_SIZE;
41
Dave Wallaced756b352017-07-03 13:11:38 -040042 if (CLIB_DEBUG > 1)
43 clib_warning ("[%d] creating segment '%s'", getpid (), ssvm->name);
44
Dave Wallaceb8856642017-07-31 13:33:11 -040045 ASSERT (vec_c_string_is_terminated (ssvm->name));
Ed Warnickecb9cada2015-12-08 15:45:58 -070046 ssvm_filename = format (0, "/dev/shm/%s%c", ssvm->name, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070047 unlink ((char *) ssvm_filename);
Dave Barach8a7fb0c2016-07-08 14:44:23 -040048 vec_free (ssvm_filename);
Ed Warnickecb9cada2015-12-08 15:45:58 -070049
Dave Barach8a7fb0c2016-07-08 14:44:23 -040050 ssvm_fd = shm_open ((char *) ssvm->name, O_RDWR | O_CREAT | O_EXCL, 0777);
Ed Warnickecb9cada2015-12-08 15:45:58 -070051 if (ssvm_fd < 0)
52 {
53 clib_unix_warning ("create segment '%s'", ssvm->name);
54 return SSVM_API_ERROR_CREATE_FAILURE;
55 }
56
Dave Wallace19296112017-08-31 15:54:11 -040057 if (fchmod (ssvm_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0)
58 clib_unix_warning ("ssvm segment chmod");
59 if (fchown (ssvm_fd, smr->uid, smr->gid) < 0)
60 clib_unix_warning ("ssvm segment chown");
61
Dave Barach56faee82016-08-04 18:58:05 -040062 if (lseek (ssvm_fd, ssvm->ssvm_size, SEEK_SET) < 0)
63 {
64 clib_unix_warning ("lseek");
65 close (ssvm_fd);
66 return SSVM_API_ERROR_SET_SIZE;
67 }
Ed Warnicke853e7202016-08-12 11:42:26 -070068
Dave Barach8a7fb0c2016-07-08 14:44:23 -040069 if (write (ssvm_fd, &junk, 1) != 1)
Ed Warnickecb9cada2015-12-08 15:45:58 -070070 {
71 clib_unix_warning ("set ssvm size");
Dave Barach8a7fb0c2016-07-08 14:44:23 -040072 close (ssvm_fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -070073 return SSVM_API_ERROR_SET_SIZE;
74 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -040075
Florin Corasb384b542018-01-15 01:08:33 -080076 page_size = clib_mem_vm_get_page_size (ssvm_fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -070077 if (ssvm->requested_va)
Florin Corasf8f516a2018-02-08 15:10:09 -080078 {
79 requested_va = ssvm->requested_va;
80 clib_mem_vm_randomize_va (&requested_va, min_log2 (page_size));
81 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070082
Florin Corasf8f516a2018-02-08 15:10:09 -080083 mapa.requested_va = requested_va;
Florin Corasb384b542018-01-15 01:08:33 -080084 mapa.size = ssvm->ssvm_size;
85 mapa.fd = ssvm_fd;
86 if (clib_mem_vm_ext_map (&mapa))
Ed Warnickecb9cada2015-12-08 15:45:58 -070087 {
88 clib_unix_warning ("mmap");
Dave Barach8a7fb0c2016-07-08 14:44:23 -040089 close (ssvm_fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -070090 return SSVM_API_ERROR_MMAP;
91 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -040092 close (ssvm_fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -070093
Florin Corasb384b542018-01-15 01:08:33 -080094 sh = mapa.addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -070095 sh->master_pid = ssvm->my_pid;
96 sh->ssvm_size = ssvm->ssvm_size;
Dave Barach8a7fb0c2016-07-08 14:44:23 -040097 sh->ssvm_va = pointer_to_uword (sh);
Florin Corasb384b542018-01-15 01:08:33 -080098 sh->type = SSVM_SEGMENT_SHM;
99 sh->heap = mheap_alloc_with_flags (((u8 *) sh) + page_size,
100 ssvm->ssvm_size - page_size, mh_flags);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700101
102 oldheap = ssvm_push_heap (sh);
Florin Corasb384b542018-01-15 01:08:33 -0800103 sh->name = format (0, "%s", ssvm->name, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700104 ssvm_pop_heap (oldheap);
105
Florin Corasb384b542018-01-15 01:08:33 -0800106 ssvm->sh = sh;
107 ssvm->my_pid = getpid ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700108 ssvm->i_am_master = 1;
109
110 /* The application has to set set sh->ready... */
111 return 0;
112}
113
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400114int
Florin Corasb384b542018-01-15 01:08:33 -0800115ssvm_slave_init_shm (ssvm_private_t * ssvm)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700116{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400117 struct stat stat;
118 int ssvm_fd = -1;
119 ssvm_shared_header_t *sh;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120
Dave Wallaceb8856642017-07-31 13:33:11 -0400121 ASSERT (vec_c_string_is_terminated (ssvm->name));
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400122 ssvm->i_am_master = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700123
Florin Corasb384b542018-01-15 01:08:33 -0800124 while (ssvm->attach_timeout-- > 0)
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400125 {
126 if (ssvm_fd < 0)
127 ssvm_fd = shm_open ((char *) ssvm->name, O_RDWR, 0777);
128 if (ssvm_fd < 0)
129 {
130 sleep (1);
131 continue;
132 }
133 if (fstat (ssvm_fd, &stat) < 0)
134 {
135 sleep (1);
136 continue;
137 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400139 if (stat.st_size > 0)
140 goto map_it;
141 }
142 clib_warning ("slave timeout");
143 return SSVM_API_ERROR_SLAVE_TIMEOUT;
144
145map_it:
146 sh = (void *) mmap (0, MMAP_PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
147 ssvm_fd, 0);
148 if (sh == MAP_FAILED)
149 {
150 clib_unix_warning ("slave research mmap");
151 close (ssvm_fd);
152 return SSVM_API_ERROR_MMAP;
153 }
154
Florin Corasb384b542018-01-15 01:08:33 -0800155 while (ssvm->attach_timeout-- > 0)
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400156 {
157 if (sh->ready)
158 goto re_map_it;
159 }
160 close (ssvm_fd);
161 munmap (sh, MMAP_PAGESIZE);
162 clib_warning ("slave timeout 2");
163 return SSVM_API_ERROR_SLAVE_TIMEOUT;
164
165re_map_it:
166 ssvm->requested_va = (u64) sh->ssvm_va;
167 ssvm->ssvm_size = sh->ssvm_size;
168 munmap (sh, MMAP_PAGESIZE);
169
170 sh = ssvm->sh = (void *) mmap ((void *) ssvm->requested_va, ssvm->ssvm_size,
171 PROT_READ | PROT_WRITE,
172 MAP_SHARED | MAP_FIXED, ssvm_fd, 0);
173
174 if (sh == MAP_FAILED)
175 {
176 clib_unix_warning ("slave final mmap");
177 close (ssvm_fd);
178 return SSVM_API_ERROR_MMAP;
179 }
180 sh->slave_pid = getpid ();
181 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700182}
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400183
Dave Barach68b0fb02017-02-28 15:15:56 -0500184void
Florin Corasb384b542018-01-15 01:08:33 -0800185ssvm_delete_shm (ssvm_private_t * ssvm)
Dave Barach68b0fb02017-02-28 15:15:56 -0500186{
187 u8 *fn;
188
189 fn = format (0, "/dev/shm/%s%c", ssvm->name, 0);
190
Dave Wallaced756b352017-07-03 13:11:38 -0400191 if (CLIB_DEBUG > 1)
192 clib_warning ("[%d] unlinking ssvm (%s) backing file '%s'", getpid (),
193 ssvm->name, fn);
194
Dave Barach68b0fb02017-02-28 15:15:56 -0500195 /* Throw away the backing file */
196 if (unlink ((char *) fn) < 0)
197 clib_unix_warning ("unlink segment '%s'", ssvm->name);
198
Dave Barach68b0fb02017-02-28 15:15:56 -0500199 vec_free (fn);
Dave Wallaced756b352017-07-03 13:11:38 -0400200 vec_free (ssvm->name);
201
202 munmap ((void *) ssvm->requested_va, ssvm->ssvm_size);
Dave Barach68b0fb02017-02-28 15:15:56 -0500203}
204
Florin Corasb384b542018-01-15 01:08:33 -0800205/**
206 * Initialize memfd segment master
207 */
Florin Coras4d9b9d82018-01-14 12:25:50 -0800208int
Florin Corasb384b542018-01-15 01:08:33 -0800209ssvm_master_init_memfd (ssvm_private_t * memfd)
Florin Coras4d9b9d82018-01-14 12:25:50 -0800210{
Florin Corasd3e83a92018-01-16 02:40:18 -0800211 uword page_size, flags = MHEAP_FLAG_DISABLE_VM | MHEAP_FLAG_THREAD_SAFE;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800212 ssvm_shared_header_t *sh;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800213 void *oldheap;
Florin Corasd3e83a92018-01-16 02:40:18 -0800214 clib_mem_vm_alloc_t alloc = { 0 };
215 clib_error_t *err;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800216
217 if (memfd->ssvm_size == 0)
218 return SSVM_API_ERROR_NO_SIZE;
219
220 ASSERT (vec_c_string_is_terminated (memfd->name));
Florin Coras4d9b9d82018-01-14 12:25:50 -0800221
Florin Corasd3e83a92018-01-16 02:40:18 -0800222 alloc.name = (char *) memfd->name;
223 alloc.size = memfd->ssvm_size;
224 alloc.flags = CLIB_MEM_VM_F_SHARED;
Florin Corasb384b542018-01-15 01:08:33 -0800225 alloc.requested_va = memfd->requested_va;
Florin Corasd3e83a92018-01-16 02:40:18 -0800226 if ((err = clib_mem_vm_ext_alloc (&alloc)))
Florin Coras4d9b9d82018-01-14 12:25:50 -0800227 {
Florin Corasd3e83a92018-01-16 02:40:18 -0800228 clib_error_report (err);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800229 return SSVM_API_ERROR_CREATE_FAILURE;
230 }
231
Florin Corasd3e83a92018-01-16 02:40:18 -0800232 memfd->fd = alloc.fd;
Florin Corasb384b542018-01-15 01:08:33 -0800233 memfd->sh = (ssvm_shared_header_t *) alloc.addr;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800234 memfd->my_pid = getpid ();
Florin Corasd3e83a92018-01-16 02:40:18 -0800235 memfd->i_am_master = 1;
236
237 page_size = 1 << alloc.log2_page_size;
Florin Corasb384b542018-01-15 01:08:33 -0800238 sh = memfd->sh;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800239 sh->master_pid = memfd->my_pid;
240 sh->ssvm_size = memfd->ssvm_size;
Florin Corasb384b542018-01-15 01:08:33 -0800241 sh->ssvm_va = pointer_to_uword (sh);
242 sh->type = SSVM_SEGMENT_MEMFD;
Florin Corasd3e83a92018-01-16 02:40:18 -0800243 sh->heap = mheap_alloc_with_flags (((u8 *) sh) + page_size,
244 memfd->ssvm_size - page_size, flags);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800245
246 oldheap = ssvm_push_heap (sh);
Florin Corasb384b542018-01-15 01:08:33 -0800247 sh->name = format (0, "%s", memfd->name, 0);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800248 ssvm_pop_heap (oldheap);
249
Florin Coras4d9b9d82018-01-14 12:25:50 -0800250 /* The application has to set set sh->ready... */
251 return 0;
252}
253
Florin Corasb384b542018-01-15 01:08:33 -0800254/**
255 * Initialize memfd segment slave
256 *
257 * Subtly different than svm_slave_init. The caller needs to acquire
258 * a usable file descriptor for the memfd segment e.g. via
259 * vppinfra/socket.c:default_socket_recvmsg
Florin Coras4d9b9d82018-01-14 12:25:50 -0800260 */
Florin Coras4d9b9d82018-01-14 12:25:50 -0800261int
262ssvm_slave_init_memfd (ssvm_private_t * memfd)
263{
Florin Corasd3e83a92018-01-16 02:40:18 -0800264 clib_mem_vm_map_t mapa = { 0 };
Florin Coras4d9b9d82018-01-14 12:25:50 -0800265 ssvm_shared_header_t *sh;
Florin Corasd3e83a92018-01-16 02:40:18 -0800266 uword page_size;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800267
268 memfd->i_am_master = 0;
269
Florin Corasd3e83a92018-01-16 02:40:18 -0800270 page_size = clib_mem_vm_get_page_size (memfd->fd);
271 if (!page_size)
272 {
273 clib_unix_warning ("page size unknown");
274 return SSVM_API_ERROR_MMAP;
275 }
276
277 /*
278 * Map the segment once, to look at the shared header
279 */
280 mapa.fd = memfd->fd;
281 mapa.size = page_size;
282
283 if (clib_mem_vm_ext_map (&mapa))
Florin Coras4d9b9d82018-01-14 12:25:50 -0800284 {
Florin Corasb384b542018-01-15 01:08:33 -0800285 clib_unix_warning ("slave research mmap (fd %d)", mapa.fd);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800286 close (memfd->fd);
287 return SSVM_API_ERROR_MMAP;
288 }
289
Florin Corasd3e83a92018-01-16 02:40:18 -0800290 sh = mapa.addr;
291 memfd->requested_va = sh->ssvm_va;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800292 memfd->ssvm_size = sh->ssvm_size;
Florin Corasb384b542018-01-15 01:08:33 -0800293 clib_mem_vm_free (sh, page_size);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800294
Florin Corasd3e83a92018-01-16 02:40:18 -0800295 /*
296 * Remap the segment at the 'right' address
297 */
298 mapa.requested_va = memfd->requested_va;
299 mapa.size = memfd->ssvm_size;
300 if (clib_mem_vm_ext_map (&mapa))
Florin Coras4d9b9d82018-01-14 12:25:50 -0800301 {
302 clib_unix_warning ("slave final mmap");
303 close (memfd->fd);
304 return SSVM_API_ERROR_MMAP;
305 }
Florin Corasd3e83a92018-01-16 02:40:18 -0800306
307 sh = mapa.addr;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800308 sh->slave_pid = getpid ();
309 memfd->sh = sh;
310 return 0;
311}
Dave Barach68b0fb02017-02-28 15:15:56 -0500312
Florin Corasd3e83a92018-01-16 02:40:18 -0800313void
314ssvm_delete_memfd (ssvm_private_t * memfd)
315{
316 vec_free (memfd->name);
317 clib_mem_vm_free (memfd->sh, memfd->ssvm_size);
318 close (memfd->fd);
319}
320
Florin Corasa332c462018-01-31 06:52:17 -0800321/**
322 * Initialize segment in a private heap
323 */
324int
325ssvm_master_init_private (ssvm_private_t * ssvm)
326{
327 u32 pagesize = clib_mem_get_page_size ();
328 ssvm_shared_header_t *sh;
329 mheap_t *heap_header;
330 u32 rnd_size = 0;
331 u8 *heap;
332
333 rnd_size = (ssvm->ssvm_size + (pagesize - 1)) & ~pagesize;
334 heap = mheap_alloc (0, rnd_size);
335 if (heap == 0)
336 {
337 clib_unix_warning ("mheap alloc");
338 return -1;
339 }
340 heap_header = mheap_header (heap);
341 heap_header->flags |= MHEAP_FLAG_THREAD_SAFE;
342
343 ssvm->ssvm_size = rnd_size;
344 ssvm->i_am_master = 1;
345 ssvm->my_pid = getpid ();
346 ssvm->requested_va = ~0;
347
348 /* Allocate a [sic] shared memory header, in process memory... */
349 sh = clib_mem_alloc_aligned (sizeof (*sh), CLIB_CACHE_LINE_BYTES);
350 ssvm->sh = sh;
351
352 memset (sh, 0, sizeof (*sh));
353 sh->heap = heap;
354 sh->type = SSVM_SEGMENT_PRIVATE;
355
356 return 0;
357}
358
359int
360ssvm_slave_init_private (ssvm_private_t * ssvm)
361{
362 clib_warning ("BUG: this should not be called!");
363 return -1;
364}
365
366void
367ssvm_delete_private (ssvm_private_t * ssvm)
368{
369 vec_free (ssvm->name);
370 mheap_free (ssvm->sh->heap);
371 clib_mem_free (ssvm->sh);
372}
373
Florin Corasb384b542018-01-15 01:08:33 -0800374int
375ssvm_master_init (ssvm_private_t * ssvm, ssvm_segment_type_t type)
376{
377 return (master_init_fns[type]) (ssvm);
378}
379
380int
381ssvm_slave_init (ssvm_private_t * ssvm, ssvm_segment_type_t type)
382{
383 return (slave_init_fns[type]) (ssvm);
384}
385
386void
387ssvm_delete (ssvm_private_t * ssvm)
388{
389 delete_fns[ssvm->sh->type] (ssvm);
390}
391
392ssvm_segment_type_t
393ssvm_type (const ssvm_private_t * ssvm)
394{
395 return ssvm->sh->type;
396}
397
398u8 *
399ssvm_name (const ssvm_private_t * ssvm)
400{
401 return ssvm->sh->name;
402}
403
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400404/*
405 * fd.io coding-style-patch-verification: ON
406 *
407 * Local Variables:
408 * eval: (c-set-style "gnu")
409 * End:
410 */