blob: c005b61144b12260dac5e05b31fc5212ad51cfd1 [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;
Florin Corasb384b542018-01-15 01:08:33 -080032 clib_mem_vm_map_t mapa = { 0 };
33 u8 junk = 0, *ssvm_filename;
Dave Barach8a7fb0c2016-07-08 14:44:23 -040034 ssvm_shared_header_t *sh;
Florin Corasf8f516a2018-02-08 15:10:09 -080035 uword page_size, requested_va = 0;
Dave Barach8a7fb0c2016-07-08 14:44:23 -040036 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -070037
38 if (ssvm->ssvm_size == 0)
39 return SSVM_API_ERROR_NO_SIZE;
40
Dave Wallaced756b352017-07-03 13:11:38 -040041 if (CLIB_DEBUG > 1)
42 clib_warning ("[%d] creating segment '%s'", getpid (), ssvm->name);
43
Dave Wallaceb8856642017-07-31 13:33:11 -040044 ASSERT (vec_c_string_is_terminated (ssvm->name));
Ed Warnickecb9cada2015-12-08 15:45:58 -070045 ssvm_filename = format (0, "/dev/shm/%s%c", ssvm->name, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070046 unlink ((char *) ssvm_filename);
Dave Barach8a7fb0c2016-07-08 14:44:23 -040047 vec_free (ssvm_filename);
Ed Warnickecb9cada2015-12-08 15:45:58 -070048
Dave Barach8a7fb0c2016-07-08 14:44:23 -040049 ssvm_fd = shm_open ((char *) ssvm->name, O_RDWR | O_CREAT | O_EXCL, 0777);
Ed Warnickecb9cada2015-12-08 15:45:58 -070050 if (ssvm_fd < 0)
51 {
52 clib_unix_warning ("create segment '%s'", ssvm->name);
53 return SSVM_API_ERROR_CREATE_FAILURE;
54 }
55
Dave Wallace19296112017-08-31 15:54:11 -040056 if (fchmod (ssvm_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0)
57 clib_unix_warning ("ssvm segment chmod");
Florin Coras65784c12018-07-04 04:17:41 -070058 if (svm_get_root_rp ())
59 {
60 /* TODO: is this really needed? */
61 svm_main_region_t *smr = svm_get_root_rp ()->data_base;
62 if (fchown (ssvm_fd, smr->uid, smr->gid) < 0)
63 clib_unix_warning ("ssvm segment chown");
64 }
Dave Wallace19296112017-08-31 15:54:11 -040065
Dave Barach56faee82016-08-04 18:58:05 -040066 if (lseek (ssvm_fd, ssvm->ssvm_size, SEEK_SET) < 0)
67 {
68 clib_unix_warning ("lseek");
69 close (ssvm_fd);
70 return SSVM_API_ERROR_SET_SIZE;
71 }
Ed Warnicke853e7202016-08-12 11:42:26 -070072
Dave Barach8a7fb0c2016-07-08 14:44:23 -040073 if (write (ssvm_fd, &junk, 1) != 1)
Ed Warnickecb9cada2015-12-08 15:45:58 -070074 {
75 clib_unix_warning ("set ssvm size");
Dave Barach8a7fb0c2016-07-08 14:44:23 -040076 close (ssvm_fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -070077 return SSVM_API_ERROR_SET_SIZE;
78 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -040079
Florin Corasb384b542018-01-15 01:08:33 -080080 page_size = clib_mem_vm_get_page_size (ssvm_fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -070081 if (ssvm->requested_va)
Florin Corasf8f516a2018-02-08 15:10:09 -080082 {
83 requested_va = ssvm->requested_va;
84 clib_mem_vm_randomize_va (&requested_va, min_log2 (page_size));
85 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070086
Florin Corasf8f516a2018-02-08 15:10:09 -080087 mapa.requested_va = requested_va;
Florin Corasb384b542018-01-15 01:08:33 -080088 mapa.size = ssvm->ssvm_size;
89 mapa.fd = ssvm_fd;
90 if (clib_mem_vm_ext_map (&mapa))
Ed Warnickecb9cada2015-12-08 15:45:58 -070091 {
92 clib_unix_warning ("mmap");
Dave Barach8a7fb0c2016-07-08 14:44:23 -040093 close (ssvm_fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -070094 return SSVM_API_ERROR_MMAP;
95 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -040096 close (ssvm_fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -070097
Florin Corasb384b542018-01-15 01:08:33 -080098 sh = mapa.addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -070099 sh->master_pid = ssvm->my_pid;
100 sh->ssvm_size = ssvm->ssvm_size;
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400101 sh->ssvm_va = pointer_to_uword (sh);
Florin Corasb384b542018-01-15 01:08:33 -0800102 sh->type = SSVM_SEGMENT_SHM;
103 sh->heap = mheap_alloc_with_flags (((u8 *) sh) + page_size,
104 ssvm->ssvm_size - page_size, mh_flags);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105
106 oldheap = ssvm_push_heap (sh);
Florin Corasb384b542018-01-15 01:08:33 -0800107 sh->name = format (0, "%s", ssvm->name, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700108 ssvm_pop_heap (oldheap);
109
Florin Corasb384b542018-01-15 01:08:33 -0800110 ssvm->sh = sh;
111 ssvm->my_pid = getpid ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700112 ssvm->i_am_master = 1;
113
114 /* The application has to set set sh->ready... */
115 return 0;
116}
117
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400118int
Florin Corasb384b542018-01-15 01:08:33 -0800119ssvm_slave_init_shm (ssvm_private_t * ssvm)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400121 struct stat stat;
122 int ssvm_fd = -1;
123 ssvm_shared_header_t *sh;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700124
Dave Wallaceb8856642017-07-31 13:33:11 -0400125 ASSERT (vec_c_string_is_terminated (ssvm->name));
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400126 ssvm->i_am_master = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700127
Florin Corasb384b542018-01-15 01:08:33 -0800128 while (ssvm->attach_timeout-- > 0)
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400129 {
130 if (ssvm_fd < 0)
131 ssvm_fd = shm_open ((char *) ssvm->name, O_RDWR, 0777);
132 if (ssvm_fd < 0)
133 {
134 sleep (1);
135 continue;
136 }
137 if (fstat (ssvm_fd, &stat) < 0)
138 {
139 sleep (1);
140 continue;
141 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700142
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400143 if (stat.st_size > 0)
144 goto map_it;
145 }
146 clib_warning ("slave timeout");
147 return SSVM_API_ERROR_SLAVE_TIMEOUT;
148
149map_it:
150 sh = (void *) mmap (0, MMAP_PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
151 ssvm_fd, 0);
152 if (sh == MAP_FAILED)
153 {
154 clib_unix_warning ("slave research mmap");
155 close (ssvm_fd);
156 return SSVM_API_ERROR_MMAP;
157 }
158
Florin Corasb384b542018-01-15 01:08:33 -0800159 while (ssvm->attach_timeout-- > 0)
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400160 {
161 if (sh->ready)
162 goto re_map_it;
163 }
164 close (ssvm_fd);
165 munmap (sh, MMAP_PAGESIZE);
166 clib_warning ("slave timeout 2");
167 return SSVM_API_ERROR_SLAVE_TIMEOUT;
168
169re_map_it:
170 ssvm->requested_va = (u64) sh->ssvm_va;
171 ssvm->ssvm_size = sh->ssvm_size;
172 munmap (sh, MMAP_PAGESIZE);
173
174 sh = ssvm->sh = (void *) mmap ((void *) ssvm->requested_va, ssvm->ssvm_size,
175 PROT_READ | PROT_WRITE,
176 MAP_SHARED | MAP_FIXED, ssvm_fd, 0);
177
178 if (sh == MAP_FAILED)
179 {
180 clib_unix_warning ("slave final mmap");
181 close (ssvm_fd);
182 return SSVM_API_ERROR_MMAP;
183 }
184 sh->slave_pid = getpid ();
185 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186}
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400187
Dave Barach68b0fb02017-02-28 15:15:56 -0500188void
Florin Corasb384b542018-01-15 01:08:33 -0800189ssvm_delete_shm (ssvm_private_t * ssvm)
Dave Barach68b0fb02017-02-28 15:15:56 -0500190{
191 u8 *fn;
192
193 fn = format (0, "/dev/shm/%s%c", ssvm->name, 0);
194
Dave Wallaced756b352017-07-03 13:11:38 -0400195 if (CLIB_DEBUG > 1)
196 clib_warning ("[%d] unlinking ssvm (%s) backing file '%s'", getpid (),
197 ssvm->name, fn);
198
Dave Barach68b0fb02017-02-28 15:15:56 -0500199 /* Throw away the backing file */
200 if (unlink ((char *) fn) < 0)
201 clib_unix_warning ("unlink segment '%s'", ssvm->name);
202
Dave Barach68b0fb02017-02-28 15:15:56 -0500203 vec_free (fn);
Dave Wallaced756b352017-07-03 13:11:38 -0400204 vec_free (ssvm->name);
205
206 munmap ((void *) ssvm->requested_va, ssvm->ssvm_size);
Dave Barach68b0fb02017-02-28 15:15:56 -0500207}
208
Florin Corasb384b542018-01-15 01:08:33 -0800209/**
210 * Initialize memfd segment master
211 */
Florin Coras4d9b9d82018-01-14 12:25:50 -0800212int
Florin Corasb384b542018-01-15 01:08:33 -0800213ssvm_master_init_memfd (ssvm_private_t * memfd)
Florin Coras4d9b9d82018-01-14 12:25:50 -0800214{
Florin Corasd3e83a92018-01-16 02:40:18 -0800215 uword page_size, flags = MHEAP_FLAG_DISABLE_VM | MHEAP_FLAG_THREAD_SAFE;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800216 ssvm_shared_header_t *sh;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800217 void *oldheap;
Florin Corasd3e83a92018-01-16 02:40:18 -0800218 clib_mem_vm_alloc_t alloc = { 0 };
219 clib_error_t *err;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800220
221 if (memfd->ssvm_size == 0)
222 return SSVM_API_ERROR_NO_SIZE;
223
224 ASSERT (vec_c_string_is_terminated (memfd->name));
Florin Coras4d9b9d82018-01-14 12:25:50 -0800225
Florin Corasd3e83a92018-01-16 02:40:18 -0800226 alloc.name = (char *) memfd->name;
227 alloc.size = memfd->ssvm_size;
228 alloc.flags = CLIB_MEM_VM_F_SHARED;
Florin Corasb384b542018-01-15 01:08:33 -0800229 alloc.requested_va = memfd->requested_va;
Florin Corasd3e83a92018-01-16 02:40:18 -0800230 if ((err = clib_mem_vm_ext_alloc (&alloc)))
Florin Coras4d9b9d82018-01-14 12:25:50 -0800231 {
Florin Corasd3e83a92018-01-16 02:40:18 -0800232 clib_error_report (err);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800233 return SSVM_API_ERROR_CREATE_FAILURE;
234 }
235
Florin Corasd3e83a92018-01-16 02:40:18 -0800236 memfd->fd = alloc.fd;
Florin Corasb384b542018-01-15 01:08:33 -0800237 memfd->sh = (ssvm_shared_header_t *) alloc.addr;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800238 memfd->my_pid = getpid ();
Florin Corasd3e83a92018-01-16 02:40:18 -0800239 memfd->i_am_master = 1;
240
241 page_size = 1 << alloc.log2_page_size;
Florin Corasb384b542018-01-15 01:08:33 -0800242 sh = memfd->sh;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800243 sh->master_pid = memfd->my_pid;
244 sh->ssvm_size = memfd->ssvm_size;
Florin Corasb384b542018-01-15 01:08:33 -0800245 sh->ssvm_va = pointer_to_uword (sh);
246 sh->type = SSVM_SEGMENT_MEMFD;
Florin Corasd3e83a92018-01-16 02:40:18 -0800247 sh->heap = mheap_alloc_with_flags (((u8 *) sh) + page_size,
248 memfd->ssvm_size - page_size, flags);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800249
250 oldheap = ssvm_push_heap (sh);
Florin Corasb384b542018-01-15 01:08:33 -0800251 sh->name = format (0, "%s", memfd->name, 0);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800252 ssvm_pop_heap (oldheap);
253
Florin Coras4d9b9d82018-01-14 12:25:50 -0800254 /* The application has to set set sh->ready... */
255 return 0;
256}
257
Florin Corasb384b542018-01-15 01:08:33 -0800258/**
259 * Initialize memfd segment slave
260 *
261 * Subtly different than svm_slave_init. The caller needs to acquire
262 * a usable file descriptor for the memfd segment e.g. via
263 * vppinfra/socket.c:default_socket_recvmsg
Florin Coras4d9b9d82018-01-14 12:25:50 -0800264 */
Florin Coras4d9b9d82018-01-14 12:25:50 -0800265int
266ssvm_slave_init_memfd (ssvm_private_t * memfd)
267{
Florin Corasd3e83a92018-01-16 02:40:18 -0800268 clib_mem_vm_map_t mapa = { 0 };
Florin Coras4d9b9d82018-01-14 12:25:50 -0800269 ssvm_shared_header_t *sh;
Florin Corasd3e83a92018-01-16 02:40:18 -0800270 uword page_size;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800271
272 memfd->i_am_master = 0;
273
Florin Corasd3e83a92018-01-16 02:40:18 -0800274 page_size = clib_mem_vm_get_page_size (memfd->fd);
275 if (!page_size)
276 {
277 clib_unix_warning ("page size unknown");
278 return SSVM_API_ERROR_MMAP;
279 }
280
281 /*
282 * Map the segment once, to look at the shared header
283 */
284 mapa.fd = memfd->fd;
285 mapa.size = page_size;
286
287 if (clib_mem_vm_ext_map (&mapa))
Florin Coras4d9b9d82018-01-14 12:25:50 -0800288 {
Florin Corasb384b542018-01-15 01:08:33 -0800289 clib_unix_warning ("slave research mmap (fd %d)", mapa.fd);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800290 close (memfd->fd);
291 return SSVM_API_ERROR_MMAP;
292 }
293
Florin Corasd3e83a92018-01-16 02:40:18 -0800294 sh = mapa.addr;
295 memfd->requested_va = sh->ssvm_va;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800296 memfd->ssvm_size = sh->ssvm_size;
Florin Corasb384b542018-01-15 01:08:33 -0800297 clib_mem_vm_free (sh, page_size);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800298
Florin Corasd3e83a92018-01-16 02:40:18 -0800299 /*
300 * Remap the segment at the 'right' address
301 */
302 mapa.requested_va = memfd->requested_va;
303 mapa.size = memfd->ssvm_size;
304 if (clib_mem_vm_ext_map (&mapa))
Florin Coras4d9b9d82018-01-14 12:25:50 -0800305 {
306 clib_unix_warning ("slave final mmap");
307 close (memfd->fd);
308 return SSVM_API_ERROR_MMAP;
309 }
Florin Corasd3e83a92018-01-16 02:40:18 -0800310
311 sh = mapa.addr;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800312 sh->slave_pid = getpid ();
313 memfd->sh = sh;
314 return 0;
315}
Dave Barach68b0fb02017-02-28 15:15:56 -0500316
Florin Corasd3e83a92018-01-16 02:40:18 -0800317void
318ssvm_delete_memfd (ssvm_private_t * memfd)
319{
320 vec_free (memfd->name);
321 clib_mem_vm_free (memfd->sh, memfd->ssvm_size);
322 close (memfd->fd);
323}
324
Florin Corasa332c462018-01-31 06:52:17 -0800325/**
326 * Initialize segment in a private heap
327 */
328int
329ssvm_master_init_private (ssvm_private_t * ssvm)
330{
331 u32 pagesize = clib_mem_get_page_size ();
332 ssvm_shared_header_t *sh;
333 mheap_t *heap_header;
Florin Coras5da96a72018-07-12 01:45:13 -0700334 u64 rnd_size = 0;
Florin Corasa332c462018-01-31 06:52:17 -0800335 u8 *heap;
336
Florin Coras5da96a72018-07-12 01:45:13 -0700337 rnd_size = (ssvm->ssvm_size + (pagesize - 1)) & ~(pagesize - 1);
338 rnd_size = clib_min (rnd_size, ((u64) 1 << 32) - pagesize);
Florin Corasa332c462018-01-31 06:52:17 -0800339 heap = mheap_alloc (0, rnd_size);
340 if (heap == 0)
341 {
342 clib_unix_warning ("mheap alloc");
343 return -1;
344 }
345 heap_header = mheap_header (heap);
346 heap_header->flags |= MHEAP_FLAG_THREAD_SAFE;
347
348 ssvm->ssvm_size = rnd_size;
349 ssvm->i_am_master = 1;
350 ssvm->my_pid = getpid ();
351 ssvm->requested_va = ~0;
352
353 /* Allocate a [sic] shared memory header, in process memory... */
354 sh = clib_mem_alloc_aligned (sizeof (*sh), CLIB_CACHE_LINE_BYTES);
355 ssvm->sh = sh;
356
357 memset (sh, 0, sizeof (*sh));
358 sh->heap = heap;
359 sh->type = SSVM_SEGMENT_PRIVATE;
360
361 return 0;
362}
363
364int
365ssvm_slave_init_private (ssvm_private_t * ssvm)
366{
367 clib_warning ("BUG: this should not be called!");
368 return -1;
369}
370
371void
372ssvm_delete_private (ssvm_private_t * ssvm)
373{
374 vec_free (ssvm->name);
375 mheap_free (ssvm->sh->heap);
376 clib_mem_free (ssvm->sh);
377}
378
Florin Corasb384b542018-01-15 01:08:33 -0800379int
380ssvm_master_init (ssvm_private_t * ssvm, ssvm_segment_type_t type)
381{
382 return (master_init_fns[type]) (ssvm);
383}
384
385int
386ssvm_slave_init (ssvm_private_t * ssvm, ssvm_segment_type_t type)
387{
388 return (slave_init_fns[type]) (ssvm);
389}
390
391void
392ssvm_delete (ssvm_private_t * ssvm)
393{
394 delete_fns[ssvm->sh->type] (ssvm);
395}
396
397ssvm_segment_type_t
398ssvm_type (const ssvm_private_t * ssvm)
399{
400 return ssvm->sh->type;
401}
402
403u8 *
404ssvm_name (const ssvm_private_t * ssvm)
405{
406 return ssvm->sh->name;
407}
408
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400409/*
410 * fd.io coding-style-patch-verification: ON
411 *
412 * Local Variables:
413 * eval: (c-set-style "gnu")
414 * End:
415 */