blob: 505521981378f94c464b249ee8cf68053cb8781a [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] =
22 { ssvm_master_init_shm, ssvm_master_init_memfd };
23static init_fn slave_init_fns[SSVM_N_SEGMENT_TYPES] =
24 { ssvm_slave_init_shm, ssvm_slave_init_memfd };
25static delete_fn delete_fns[SSVM_N_SEGMENT_TYPES] =
26 { ssvm_delete_shm, ssvm_delete_memfd };
27
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 Corasb384b542018-01-15 01:08:33 -080036 uword page_size;
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 Corasb384b542018-01-15 01:08:33 -080078 clib_mem_vm_randomize_va (&ssvm->requested_va, min_log2 (page_size));
Ed Warnickecb9cada2015-12-08 15:45:58 -070079
Florin Corasb384b542018-01-15 01:08:33 -080080 mapa.requested_va = ssvm->requested_va;
81 mapa.size = ssvm->ssvm_size;
82 mapa.fd = ssvm_fd;
83 if (clib_mem_vm_ext_map (&mapa))
Ed Warnickecb9cada2015-12-08 15:45:58 -070084 {
85 clib_unix_warning ("mmap");
Dave Barach8a7fb0c2016-07-08 14:44:23 -040086 close (ssvm_fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -070087 return SSVM_API_ERROR_MMAP;
88 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -040089 close (ssvm_fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -070090
Florin Corasb384b542018-01-15 01:08:33 -080091 sh = mapa.addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -070092 sh->master_pid = ssvm->my_pid;
93 sh->ssvm_size = ssvm->ssvm_size;
Dave Barach8a7fb0c2016-07-08 14:44:23 -040094 sh->ssvm_va = pointer_to_uword (sh);
Florin Corasb384b542018-01-15 01:08:33 -080095 sh->type = SSVM_SEGMENT_SHM;
96 sh->heap = mheap_alloc_with_flags (((u8 *) sh) + page_size,
97 ssvm->ssvm_size - page_size, mh_flags);
Ed Warnickecb9cada2015-12-08 15:45:58 -070098
99 oldheap = ssvm_push_heap (sh);
Florin Corasb384b542018-01-15 01:08:33 -0800100 sh->name = format (0, "%s", ssvm->name, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700101 ssvm_pop_heap (oldheap);
102
Florin Corasb384b542018-01-15 01:08:33 -0800103 ssvm->sh = sh;
104 ssvm->my_pid = getpid ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105 ssvm->i_am_master = 1;
106
107 /* The application has to set set sh->ready... */
108 return 0;
109}
110
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400111int
Florin Corasb384b542018-01-15 01:08:33 -0800112ssvm_slave_init_shm (ssvm_private_t * ssvm)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700113{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400114 struct stat stat;
115 int ssvm_fd = -1;
116 ssvm_shared_header_t *sh;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700117
Dave Wallaceb8856642017-07-31 13:33:11 -0400118 ASSERT (vec_c_string_is_terminated (ssvm->name));
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400119 ssvm->i_am_master = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120
Florin Corasb384b542018-01-15 01:08:33 -0800121 while (ssvm->attach_timeout-- > 0)
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400122 {
123 if (ssvm_fd < 0)
124 ssvm_fd = shm_open ((char *) ssvm->name, O_RDWR, 0777);
125 if (ssvm_fd < 0)
126 {
127 sleep (1);
128 continue;
129 }
130 if (fstat (ssvm_fd, &stat) < 0)
131 {
132 sleep (1);
133 continue;
134 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700135
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400136 if (stat.st_size > 0)
137 goto map_it;
138 }
139 clib_warning ("slave timeout");
140 return SSVM_API_ERROR_SLAVE_TIMEOUT;
141
142map_it:
143 sh = (void *) mmap (0, MMAP_PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
144 ssvm_fd, 0);
145 if (sh == MAP_FAILED)
146 {
147 clib_unix_warning ("slave research mmap");
148 close (ssvm_fd);
149 return SSVM_API_ERROR_MMAP;
150 }
151
Florin Corasb384b542018-01-15 01:08:33 -0800152 while (ssvm->attach_timeout-- > 0)
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400153 {
154 if (sh->ready)
155 goto re_map_it;
156 }
157 close (ssvm_fd);
158 munmap (sh, MMAP_PAGESIZE);
159 clib_warning ("slave timeout 2");
160 return SSVM_API_ERROR_SLAVE_TIMEOUT;
161
162re_map_it:
163 ssvm->requested_va = (u64) sh->ssvm_va;
164 ssvm->ssvm_size = sh->ssvm_size;
165 munmap (sh, MMAP_PAGESIZE);
166
167 sh = ssvm->sh = (void *) mmap ((void *) ssvm->requested_va, ssvm->ssvm_size,
168 PROT_READ | PROT_WRITE,
169 MAP_SHARED | MAP_FIXED, ssvm_fd, 0);
170
171 if (sh == MAP_FAILED)
172 {
173 clib_unix_warning ("slave final mmap");
174 close (ssvm_fd);
175 return SSVM_API_ERROR_MMAP;
176 }
177 sh->slave_pid = getpid ();
178 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700179}
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400180
Dave Barach68b0fb02017-02-28 15:15:56 -0500181void
Florin Corasb384b542018-01-15 01:08:33 -0800182ssvm_delete_shm (ssvm_private_t * ssvm)
Dave Barach68b0fb02017-02-28 15:15:56 -0500183{
184 u8 *fn;
185
186 fn = format (0, "/dev/shm/%s%c", ssvm->name, 0);
187
Dave Wallaced756b352017-07-03 13:11:38 -0400188 if (CLIB_DEBUG > 1)
189 clib_warning ("[%d] unlinking ssvm (%s) backing file '%s'", getpid (),
190 ssvm->name, fn);
191
Dave Barach68b0fb02017-02-28 15:15:56 -0500192 /* Throw away the backing file */
193 if (unlink ((char *) fn) < 0)
194 clib_unix_warning ("unlink segment '%s'", ssvm->name);
195
Dave Barach68b0fb02017-02-28 15:15:56 -0500196 vec_free (fn);
Dave Wallaced756b352017-07-03 13:11:38 -0400197 vec_free (ssvm->name);
198
199 munmap ((void *) ssvm->requested_va, ssvm->ssvm_size);
Dave Barach68b0fb02017-02-28 15:15:56 -0500200}
201
Florin Corasb384b542018-01-15 01:08:33 -0800202/**
203 * Initialize memfd segment master
204 */
Florin Coras4d9b9d82018-01-14 12:25:50 -0800205int
Florin Corasb384b542018-01-15 01:08:33 -0800206ssvm_master_init_memfd (ssvm_private_t * memfd)
Florin Coras4d9b9d82018-01-14 12:25:50 -0800207{
Florin Corasd3e83a92018-01-16 02:40:18 -0800208 uword page_size, flags = MHEAP_FLAG_DISABLE_VM | MHEAP_FLAG_THREAD_SAFE;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800209 ssvm_shared_header_t *sh;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800210 void *oldheap;
Florin Corasd3e83a92018-01-16 02:40:18 -0800211 clib_mem_vm_alloc_t alloc = { 0 };
212 clib_error_t *err;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800213
214 if (memfd->ssvm_size == 0)
215 return SSVM_API_ERROR_NO_SIZE;
216
217 ASSERT (vec_c_string_is_terminated (memfd->name));
Florin Coras4d9b9d82018-01-14 12:25:50 -0800218
Florin Corasd3e83a92018-01-16 02:40:18 -0800219 alloc.name = (char *) memfd->name;
220 alloc.size = memfd->ssvm_size;
221 alloc.flags = CLIB_MEM_VM_F_SHARED;
Florin Corasb384b542018-01-15 01:08:33 -0800222 alloc.requested_va = memfd->requested_va;
Florin Corasd3e83a92018-01-16 02:40:18 -0800223 if ((err = clib_mem_vm_ext_alloc (&alloc)))
Florin Coras4d9b9d82018-01-14 12:25:50 -0800224 {
Florin Corasd3e83a92018-01-16 02:40:18 -0800225 clib_error_report (err);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800226 return SSVM_API_ERROR_CREATE_FAILURE;
227 }
228
Florin Corasd3e83a92018-01-16 02:40:18 -0800229 memfd->fd = alloc.fd;
Florin Corasb384b542018-01-15 01:08:33 -0800230 memfd->sh = (ssvm_shared_header_t *) alloc.addr;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800231 memfd->my_pid = getpid ();
Florin Corasd3e83a92018-01-16 02:40:18 -0800232 memfd->i_am_master = 1;
233
234 page_size = 1 << alloc.log2_page_size;
Florin Corasb384b542018-01-15 01:08:33 -0800235 sh = memfd->sh;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800236 sh->master_pid = memfd->my_pid;
237 sh->ssvm_size = memfd->ssvm_size;
Florin Corasb384b542018-01-15 01:08:33 -0800238 sh->ssvm_va = pointer_to_uword (sh);
239 sh->type = SSVM_SEGMENT_MEMFD;
Florin Corasd3e83a92018-01-16 02:40:18 -0800240 sh->heap = mheap_alloc_with_flags (((u8 *) sh) + page_size,
241 memfd->ssvm_size - page_size, flags);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800242
243 oldheap = ssvm_push_heap (sh);
Florin Corasb384b542018-01-15 01:08:33 -0800244 sh->name = format (0, "%s", memfd->name, 0);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800245 ssvm_pop_heap (oldheap);
246
Florin Coras4d9b9d82018-01-14 12:25:50 -0800247 /* The application has to set set sh->ready... */
248 return 0;
249}
250
Florin Corasb384b542018-01-15 01:08:33 -0800251/**
252 * Initialize memfd segment slave
253 *
254 * Subtly different than svm_slave_init. The caller needs to acquire
255 * a usable file descriptor for the memfd segment e.g. via
256 * vppinfra/socket.c:default_socket_recvmsg
Florin Coras4d9b9d82018-01-14 12:25:50 -0800257 */
Florin Coras4d9b9d82018-01-14 12:25:50 -0800258int
259ssvm_slave_init_memfd (ssvm_private_t * memfd)
260{
Florin Corasd3e83a92018-01-16 02:40:18 -0800261 clib_mem_vm_map_t mapa = { 0 };
Florin Coras4d9b9d82018-01-14 12:25:50 -0800262 ssvm_shared_header_t *sh;
Florin Corasd3e83a92018-01-16 02:40:18 -0800263 uword page_size;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800264
265 memfd->i_am_master = 0;
266
Florin Corasd3e83a92018-01-16 02:40:18 -0800267 page_size = clib_mem_vm_get_page_size (memfd->fd);
268 if (!page_size)
269 {
270 clib_unix_warning ("page size unknown");
271 return SSVM_API_ERROR_MMAP;
272 }
273
274 /*
275 * Map the segment once, to look at the shared header
276 */
277 mapa.fd = memfd->fd;
278 mapa.size = page_size;
279
280 if (clib_mem_vm_ext_map (&mapa))
Florin Coras4d9b9d82018-01-14 12:25:50 -0800281 {
Florin Corasb384b542018-01-15 01:08:33 -0800282 clib_unix_warning ("slave research mmap (fd %d)", mapa.fd);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800283 close (memfd->fd);
284 return SSVM_API_ERROR_MMAP;
285 }
286
Florin Corasd3e83a92018-01-16 02:40:18 -0800287 sh = mapa.addr;
288 memfd->requested_va = sh->ssvm_va;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800289 memfd->ssvm_size = sh->ssvm_size;
Florin Corasb384b542018-01-15 01:08:33 -0800290 clib_mem_vm_free (sh, page_size);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800291
Florin Corasd3e83a92018-01-16 02:40:18 -0800292 /*
293 * Remap the segment at the 'right' address
294 */
295 mapa.requested_va = memfd->requested_va;
296 mapa.size = memfd->ssvm_size;
297 if (clib_mem_vm_ext_map (&mapa))
Florin Coras4d9b9d82018-01-14 12:25:50 -0800298 {
299 clib_unix_warning ("slave final mmap");
300 close (memfd->fd);
301 return SSVM_API_ERROR_MMAP;
302 }
Florin Corasd3e83a92018-01-16 02:40:18 -0800303
304 sh = mapa.addr;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800305 sh->slave_pid = getpid ();
306 memfd->sh = sh;
307 return 0;
308}
Dave Barach68b0fb02017-02-28 15:15:56 -0500309
Florin Corasd3e83a92018-01-16 02:40:18 -0800310void
311ssvm_delete_memfd (ssvm_private_t * memfd)
312{
313 vec_free (memfd->name);
314 clib_mem_vm_free (memfd->sh, memfd->ssvm_size);
315 close (memfd->fd);
316}
317
Florin Corasb384b542018-01-15 01:08:33 -0800318int
319ssvm_master_init (ssvm_private_t * ssvm, ssvm_segment_type_t type)
320{
321 return (master_init_fns[type]) (ssvm);
322}
323
324int
325ssvm_slave_init (ssvm_private_t * ssvm, ssvm_segment_type_t type)
326{
327 return (slave_init_fns[type]) (ssvm);
328}
329
330void
331ssvm_delete (ssvm_private_t * ssvm)
332{
333 delete_fns[ssvm->sh->type] (ssvm);
334}
335
336ssvm_segment_type_t
337ssvm_type (const ssvm_private_t * ssvm)
338{
339 return ssvm->sh->type;
340}
341
342u8 *
343ssvm_name (const ssvm_private_t * ssvm)
344{
345 return ssvm->sh->name;
346}
347
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400348/*
349 * fd.io coding-style-patch-verification: ON
350 *
351 * Local Variables:
352 * eval: (c-set-style "gnu")
353 * End:
354 */