blob: 36abc208636332670b8c95cb18bb15f49f0737b8 [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
Dave Barach8a7fb0c2016-07-08 14:44:23 -040018int
19ssvm_master_init (ssvm_private_t * ssvm, u32 master_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -070020{
Dave Wallace19296112017-08-31 15:54:11 -040021 svm_main_region_t *smr = svm_get_root_rp ()->data_base;
Ed Warnickecb9cada2015-12-08 15:45:58 -070022 int ssvm_fd;
Dave Barach8a7fb0c2016-07-08 14:44:23 -040023 u8 *ssvm_filename;
Ed Warnickecb9cada2015-12-08 15:45:58 -070024 u8 junk = 0;
25 int flags;
Dave Barach8a7fb0c2016-07-08 14:44:23 -040026 ssvm_shared_header_t *sh;
27 u64 ticks = clib_cpu_time_now ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070028 u64 randomize_baseva;
Dave Barach8a7fb0c2016-07-08 14:44:23 -040029 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -070030
31 if (ssvm->ssvm_size == 0)
32 return SSVM_API_ERROR_NO_SIZE;
33
Dave Wallaced756b352017-07-03 13:11:38 -040034 if (CLIB_DEBUG > 1)
35 clib_warning ("[%d] creating segment '%s'", getpid (), ssvm->name);
36
Dave Wallaceb8856642017-07-31 13:33:11 -040037 ASSERT (vec_c_string_is_terminated (ssvm->name));
Ed Warnickecb9cada2015-12-08 15:45:58 -070038 ssvm_filename = format (0, "/dev/shm/%s%c", ssvm->name, 0);
39
40 unlink ((char *) ssvm_filename);
41
Dave Barach8a7fb0c2016-07-08 14:44:23 -040042 vec_free (ssvm_filename);
Ed Warnickecb9cada2015-12-08 15:45:58 -070043
Dave Barach8a7fb0c2016-07-08 14:44:23 -040044 ssvm_fd = shm_open ((char *) ssvm->name, O_RDWR | O_CREAT | O_EXCL, 0777);
Ed Warnickecb9cada2015-12-08 15:45:58 -070045
46 if (ssvm_fd < 0)
47 {
48 clib_unix_warning ("create segment '%s'", ssvm->name);
49 return SSVM_API_ERROR_CREATE_FAILURE;
50 }
51
Dave Wallace19296112017-08-31 15:54:11 -040052 if (fchmod (ssvm_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0)
53 clib_unix_warning ("ssvm segment chmod");
54 if (fchown (ssvm_fd, smr->uid, smr->gid) < 0)
55 clib_unix_warning ("ssvm segment chown");
56
Dave Barach56faee82016-08-04 18:58:05 -040057 if (lseek (ssvm_fd, ssvm->ssvm_size, SEEK_SET) < 0)
58 {
59 clib_unix_warning ("lseek");
60 close (ssvm_fd);
61 return SSVM_API_ERROR_SET_SIZE;
62 }
Ed Warnicke853e7202016-08-12 11:42:26 -070063
Dave Barach8a7fb0c2016-07-08 14:44:23 -040064 if (write (ssvm_fd, &junk, 1) != 1)
Ed Warnickecb9cada2015-12-08 15:45:58 -070065 {
66 clib_unix_warning ("set ssvm size");
Dave Barach8a7fb0c2016-07-08 14:44:23 -040067 close (ssvm_fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -070068 return SSVM_API_ERROR_SET_SIZE;
69 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -040070
Ed Warnickecb9cada2015-12-08 15:45:58 -070071 flags = MAP_SHARED;
72 if (ssvm->requested_va)
73 flags |= MAP_FIXED;
74
75 randomize_baseva = (ticks & 15) * MMAP_PAGESIZE;
76
77 if (ssvm->requested_va)
78 ssvm->requested_va += randomize_baseva;
Dave Barach8a7fb0c2016-07-08 14:44:23 -040079
80 sh = ssvm->sh =
81 (ssvm_shared_header_t *) mmap ((void *) ssvm->requested_va,
82 ssvm->ssvm_size, PROT_READ | PROT_WRITE,
83 flags, ssvm_fd, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070084
Christophe Fontainefef15b42016-04-09 12:38:49 +090085 if (ssvm->sh == MAP_FAILED)
Ed Warnickecb9cada2015-12-08 15:45:58 -070086 {
87 clib_unix_warning ("mmap");
Dave Barach8a7fb0c2016-07-08 14:44:23 -040088 close (ssvm_fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -070089 return SSVM_API_ERROR_MMAP;
90 }
91
Dave Barach8a7fb0c2016-07-08 14:44:23 -040092 close (ssvm_fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -070093
Dave Barach8a7fb0c2016-07-08 14:44:23 -040094 ssvm->my_pid = getpid ();
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->heap = mheap_alloc_with_flags
98 (((u8 *) sh) + MMAP_PAGESIZE, ssvm->ssvm_size - MMAP_PAGESIZE,
Ed Warnickecb9cada2015-12-08 15:45:58 -070099 MHEAP_FLAG_DISABLE_VM | MHEAP_FLAG_THREAD_SAFE);
100
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400101 sh->ssvm_va = pointer_to_uword (sh);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700102 sh->master_index = master_index;
103
104 oldheap = ssvm_push_heap (sh);
105 sh->name = format (0, "%s%c", ssvm->name, 0);
106 ssvm_pop_heap (oldheap);
107
108 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
115ssvm_slave_init (ssvm_private_t * ssvm, int timeout_in_seconds)
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
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400124 while (timeout_in_seconds-- > 0)
125 {
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
155 while (timeout_in_seconds-- > 0)
156 {
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
185ssvm_delete (ssvm_private_t * ssvm)
186{
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 Coras4d9b9d82018-01-14 12:25:50 -0800205int
206ssvm_master_init_memfd (ssvm_private_t * memfd, u32 master_index)
207{
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 Corasd3e83a92018-01-16 02:40:18 -0800218 memfd->name = format (0, "memfd svm region %d%c", master_index, 0);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800219
Florin Corasd3e83a92018-01-16 02:40:18 -0800220 alloc.name = (char *) memfd->name;
221 alloc.size = memfd->ssvm_size;
222 alloc.flags = CLIB_MEM_VM_F_SHARED;
223 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;
230 memfd->sh = 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;
235 sh = (ssvm_shared_header_t *) memfd->sh;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800236 sh->master_pid = memfd->my_pid;
237 sh->ssvm_size = memfd->ssvm_size;
Florin Corasd3e83a92018-01-16 02:40:18 -0800238 sh->heap = mheap_alloc_with_flags (((u8 *) sh) + page_size,
239 memfd->ssvm_size - page_size, flags);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800240 sh->ssvm_va = pointer_to_uword (sh);
241 sh->master_index = master_index;
242
243 oldheap = ssvm_push_heap (sh);
244 sh->name = format (0, "%s%c", memfd->name, 0);
245 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
251/*
252 * Subtly different than svm_slave_init. The caller
253 * needs to acquire a usable file descriptor for the memfd segment
254 * e.g. via vppinfra/socket.c:default_socket_recvmsg
255 */
256
257int
258ssvm_slave_init_memfd (ssvm_private_t * memfd)
259{
Florin Corasd3e83a92018-01-16 02:40:18 -0800260 clib_mem_vm_map_t mapa = { 0 };
Florin Coras4d9b9d82018-01-14 12:25:50 -0800261 ssvm_shared_header_t *sh;
Florin Corasd3e83a92018-01-16 02:40:18 -0800262 uword page_size;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800263
264 memfd->i_am_master = 0;
265
Florin Corasd3e83a92018-01-16 02:40:18 -0800266 page_size = clib_mem_vm_get_page_size (memfd->fd);
267 if (!page_size)
268 {
269 clib_unix_warning ("page size unknown");
270 return SSVM_API_ERROR_MMAP;
271 }
272
273 /*
274 * Map the segment once, to look at the shared header
275 */
276 mapa.fd = memfd->fd;
277 mapa.size = page_size;
278
279 if (clib_mem_vm_ext_map (&mapa))
Florin Coras4d9b9d82018-01-14 12:25:50 -0800280 {
281 clib_unix_warning ("slave research mmap");
282 close (memfd->fd);
283 return SSVM_API_ERROR_MMAP;
284 }
285
Florin Corasd3e83a92018-01-16 02:40:18 -0800286 sh = mapa.addr;
287 memfd->requested_va = sh->ssvm_va;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800288 memfd->ssvm_size = sh->ssvm_size;
Florin Corasd3e83a92018-01-16 02:40:18 -0800289 munmap (sh, page_size);
Florin Coras4d9b9d82018-01-14 12:25:50 -0800290
Florin Corasd3e83a92018-01-16 02:40:18 -0800291 /*
292 * Remap the segment at the 'right' address
293 */
294 mapa.requested_va = memfd->requested_va;
295 mapa.size = memfd->ssvm_size;
296 if (clib_mem_vm_ext_map (&mapa))
Florin Coras4d9b9d82018-01-14 12:25:50 -0800297 {
298 clib_unix_warning ("slave final mmap");
299 close (memfd->fd);
300 return SSVM_API_ERROR_MMAP;
301 }
Florin Corasd3e83a92018-01-16 02:40:18 -0800302
303 sh = mapa.addr;
Florin Coras4d9b9d82018-01-14 12:25:50 -0800304 sh->slave_pid = getpid ();
305 memfd->sh = sh;
306 return 0;
307}
Dave Barach68b0fb02017-02-28 15:15:56 -0500308
Florin Corasd3e83a92018-01-16 02:40:18 -0800309void
310ssvm_delete_memfd (ssvm_private_t * memfd)
311{
312 vec_free (memfd->name);
313 clib_mem_vm_free (memfd->sh, memfd->ssvm_size);
314 close (memfd->fd);
315}
316
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400317/*
318 * fd.io coding-style-patch-verification: ON
319 *
320 * Local Variables:
321 * eval: (c-set-style "gnu")
322 * End:
323 */