blob: 53976fbedf9d1e8c134a1ab345992521d13f7b13 [file] [log] [blame]
Dave Barach371e4e12016-07-08 09:38:52 -04001/*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002 *------------------------------------------------------------------
3 * memclnt_shared.c - API message handling, common code for both clients
4 * and the vlib process itself.
Dave Barach371e4e12016-07-08 09:38:52 -04005 *
Ed Warnickecb9cada2015-12-08 15:45:58 -07006 *
7 * Copyright (c) 2009 Cisco and/or its affiliates.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at:
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *------------------------------------------------------------------
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
Ole Troan6855f6c2016-04-09 03:16:30 +020024#include <stddef.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070025#include <string.h>
26#include <unistd.h>
27#include <signal.h>
28#include <vppinfra/format.h>
29#include <vppinfra/byte_order.h>
30#include <vppinfra/error.h>
31#include <vlib/vlib.h>
32#include <vlib/unix/unix.h>
33#include <vlibmemory/api.h>
34#include <vlibmemory/unix_shared_memory_queue.h>
35
Dave Barach371e4e12016-07-08 09:38:52 -040036#include <vlibmemory/vl_memory_msg_enum.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070037
Dave Barach371e4e12016-07-08 09:38:52 -040038#define vl_typedefs
Ed Warnickecb9cada2015-12-08 15:45:58 -070039#include <vlibmemory/vl_memory_api_h.h>
40#undef vl_typedefs
41
Dave Barach371e4e12016-07-08 09:38:52 -040042static inline void *
43vl_msg_api_alloc_internal (int nbytes, int pool)
Ed Warnickecb9cada2015-12-08 15:45:58 -070044{
Dave Barach371e4e12016-07-08 09:38:52 -040045 int i;
46 msgbuf_t *rv;
47 ring_alloc_t *ap;
48 unix_shared_memory_queue_t *q;
49 void *oldheap;
50 vl_shmem_hdr_t *shmem_hdr;
51 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -070052
Dave Barach371e4e12016-07-08 09:38:52 -040053 shmem_hdr = am->shmem_hdr;
Ed Warnickecb9cada2015-12-08 15:45:58 -070054
Dave Barach371e4e12016-07-08 09:38:52 -040055 if (shmem_hdr == 0)
56 {
57 clib_warning ("shared memory header NULL");
58 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -070059 }
60
Dave Barach371e4e12016-07-08 09:38:52 -040061 /* account for the msgbuf_t header */
62 nbytes += sizeof (msgbuf_t);
Ed Warnickecb9cada2015-12-08 15:45:58 -070063
Dave Barach371e4e12016-07-08 09:38:52 -040064 if (shmem_hdr->vl_rings == 0)
65 {
66 clib_warning ("vl_rings NULL");
67 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -070068 }
69
Dave Barach371e4e12016-07-08 09:38:52 -040070 if (shmem_hdr->client_rings == 0)
71 {
72 clib_warning ("client_rings NULL");
73 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -070074 }
75
Dave Barach371e4e12016-07-08 09:38:52 -040076 ap = pool ? shmem_hdr->vl_rings : shmem_hdr->client_rings;
77 for (i = 0; i < vec_len (ap); i++)
78 {
79 /* Too big? */
80 if (nbytes > ap[i].size)
81 {
82 continue;
83 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070084
Dave Barach371e4e12016-07-08 09:38:52 -040085 q = ap[i].rp;
86 if (pool == 0)
87 {
88 pthread_mutex_lock (&q->mutex);
89 }
90 rv = (msgbuf_t *) (&q->data[0] + q->head * q->elsize);
91 /*
92 * Is this item still in use?
93 */
94 if (rv->q)
95 {
96 /* yes, loser; try next larger pool */
97 ap[i].misses++;
98 if (pool == 0)
99 pthread_mutex_unlock (&q->mutex);
100 continue;
101 }
102 /* OK, we have a winner */
103 ap[i].hits++;
104 /*
105 * Remember the source queue, although we
106 * don't need to know the queue to free the item.
107 */
108 rv->q = q;
109 q->head++;
110 if (q->head == q->maxsize)
111 q->head = 0;
112
113 if (pool == 0)
114 pthread_mutex_unlock (&q->mutex);
115 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700116 }
117
Dave Barach371e4e12016-07-08 09:38:52 -0400118 /*
119 * Request too big, or head element of all size-compatible rings
120 * still in use. Fall back to shared-memory malloc.
121 */
122 am->ring_misses++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700123
Dave Barach371e4e12016-07-08 09:38:52 -0400124 pthread_mutex_lock (&am->vlib_rp->mutex);
125 oldheap = svm_push_data_heap (am->vlib_rp);
126 rv = clib_mem_alloc (nbytes);
127 rv->q = 0;
128 svm_pop_heap (oldheap);
129 pthread_mutex_unlock (&am->vlib_rp->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130
Dave Barach371e4e12016-07-08 09:38:52 -0400131out:
132 rv->data_len = htonl (nbytes - sizeof (msgbuf_t));
133 return (rv->data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134}
135
Dave Barach371e4e12016-07-08 09:38:52 -0400136void *
137vl_msg_api_alloc (int nbytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138{
Dave Barach371e4e12016-07-08 09:38:52 -0400139 int pool;
140 api_main_t *am = &api_main;
141 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700142
Dave Barach371e4e12016-07-08 09:38:52 -0400143 /*
144 * Clients use pool-0, vlib proc uses pool 1
145 */
146 pool = (am->our_pid == shmem_hdr->vl_pid);
147 return vl_msg_api_alloc_internal (nbytes, pool);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700148}
149
Dave Barach371e4e12016-07-08 09:38:52 -0400150void *
151vl_msg_api_alloc_as_if_client (int nbytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700152{
Dave Barach371e4e12016-07-08 09:38:52 -0400153 return vl_msg_api_alloc_internal (nbytes, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154}
155
Dave Barach371e4e12016-07-08 09:38:52 -0400156void
157vl_msg_api_free (void *a)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700158{
Dave Barach371e4e12016-07-08 09:38:52 -0400159 msgbuf_t *rv;
160 void *oldheap;
161 api_main_t *am = &api_main;
Ole Troan6855f6c2016-04-09 03:16:30 +0200162
Dave Barach371e4e12016-07-08 09:38:52 -0400163 rv = (msgbuf_t *) (((u8 *) a) - offsetof (msgbuf_t, data));
164
165 /*
166 * Here's the beauty of the scheme. Only one proc/thread has
167 * control of a given message buffer. To free a buffer, we just clear the
168 * queue field, and leave. No locks, no hits, no errors...
169 */
170 if (rv->q)
171 {
172 rv->q = 0;
173 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700174 }
175
Dave Barach371e4e12016-07-08 09:38:52 -0400176 pthread_mutex_lock (&am->vlib_rp->mutex);
177 oldheap = svm_push_data_heap (am->vlib_rp);
178 clib_mem_free (rv);
179 svm_pop_heap (oldheap);
180 pthread_mutex_unlock (&am->vlib_rp->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700181}
182
Dave Barach371e4e12016-07-08 09:38:52 -0400183static void
184vl_msg_api_free_nolock (void *a)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700185{
Dave Barach371e4e12016-07-08 09:38:52 -0400186 msgbuf_t *rv;
187 void *oldheap;
188 api_main_t *am = &api_main;
189
190 rv = (msgbuf_t *) (((u8 *) a) - offsetof (msgbuf_t, data));
191 /*
192 * Here's the beauty of the scheme. Only one proc/thread has
193 * control of a given message buffer. To free a buffer, we just clear the
194 * queue field, and leave. No locks, no hits, no errors...
195 */
196 if (rv->q)
197 {
198 rv->q = 0;
199 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200 }
201
Dave Barach371e4e12016-07-08 09:38:52 -0400202 oldheap = svm_push_data_heap (am->vlib_rp);
203 clib_mem_free (rv);
204 svm_pop_heap (oldheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205}
206
Dave Barach371e4e12016-07-08 09:38:52 -0400207void
208vl_set_memory_root_path (char *name)
Dave Barach309bef22016-01-22 16:09:52 -0500209{
Dave Barach371e4e12016-07-08 09:38:52 -0400210 api_main_t *am = &api_main;
Dave Barach309bef22016-01-22 16:09:52 -0500211
Dave Barach371e4e12016-07-08 09:38:52 -0400212 am->root_path = name;
Dave Barach309bef22016-01-22 16:09:52 -0500213}
214
Dave Barach371e4e12016-07-08 09:38:52 -0400215void
216vl_set_memory_uid (int uid)
Dave Barach16c75df2016-05-31 14:05:46 -0400217{
Dave Barach371e4e12016-07-08 09:38:52 -0400218 api_main_t *am = &api_main;
Dave Barach16c75df2016-05-31 14:05:46 -0400219
Dave Barach371e4e12016-07-08 09:38:52 -0400220 am->api_uid = uid;
Dave Barach16c75df2016-05-31 14:05:46 -0400221}
222
Dave Barach371e4e12016-07-08 09:38:52 -0400223void
224vl_set_memory_gid (int gid)
Dave Barach16c75df2016-05-31 14:05:46 -0400225{
Dave Barach371e4e12016-07-08 09:38:52 -0400226 api_main_t *am = &api_main;
Dave Barach16c75df2016-05-31 14:05:46 -0400227
Dave Barach371e4e12016-07-08 09:38:52 -0400228 am->api_gid = gid;
Dave Barach16c75df2016-05-31 14:05:46 -0400229}
230
Dave Barach371e4e12016-07-08 09:38:52 -0400231int
232vl_map_shmem (char *region_name, int is_vlib)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233{
Dave Barach371e4e12016-07-08 09:38:52 -0400234 svm_map_region_args_t _a, *a = &_a;
235 svm_region_t *vlib_rp, *root_rp;
236 void *oldheap;
237 vl_shmem_hdr_t *shmem_hdr = 0;
238 api_main_t *am = &api_main;
239 int i;
240 struct timespec ts, tsrem;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241
Dave Barach371e4e12016-07-08 09:38:52 -0400242 if (is_vlib == 0)
243 svm_region_init_chroot (am->root_path);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244
Dave Barach371e4e12016-07-08 09:38:52 -0400245 memset (a, 0, sizeof (*a));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700246
Dave Barach371e4e12016-07-08 09:38:52 -0400247 a->name = region_name;
248 a->size = 16 << 20;
249 a->flags = SVM_FLAGS_MHEAP;
250 a->uid = am->api_uid;
251 a->gid = am->api_gid;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700252
Dave Barach371e4e12016-07-08 09:38:52 -0400253 vlib_rp = svm_region_find_or_create (a);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254
Dave Barach371e4e12016-07-08 09:38:52 -0400255 if (vlib_rp == 0)
256 return (-2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257
Dave Barach371e4e12016-07-08 09:38:52 -0400258 pthread_mutex_lock (&vlib_rp->mutex);
259 /* Has someone else set up the shared-memory variable table? */
260 if (vlib_rp->user_ctx)
261 {
262 am->shmem_hdr = (void *) vlib_rp->user_ctx;
263 am->our_pid = getpid ();
264 if (is_vlib)
265 {
266 unix_shared_memory_queue_t *q;
267 uword old_msg;
268 /*
269 * application restart. Reset cached pids, API message
270 * rings, list of clients; otherwise, various things
271 * fail. (e.g. queue non-empty notification)
272 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273
Dave Barach371e4e12016-07-08 09:38:52 -0400274 /* ghosts keep the region from disappearing properly */
275 svm_client_scan_this_region_nolock (vlib_rp);
276 am->shmem_hdr->application_restarts++;
277 q = am->shmem_hdr->vl_input_queue;
278 am->shmem_hdr->vl_pid = getpid ();
279 q->consumer_pid = am->shmem_hdr->vl_pid;
280 /* Drain the input queue, freeing msgs */
281 for (i = 0; i < 10; i++)
282 {
283 if (pthread_mutex_trylock (&q->mutex) == 0)
284 {
285 pthread_mutex_unlock (&q->mutex);
286 goto mutex_ok;
287 }
288 ts.tv_sec = 0;
289 ts.tv_nsec = 10000 * 1000; /* 10 ms */
290 while (nanosleep (&ts, &tsrem) < 0)
291 ts = tsrem;
292 }
293 /* Mutex buggered, "fix" it */
294 memset (&q->mutex, 0, sizeof (q->mutex));
295 clib_warning ("forcibly release main input queue mutex");
296
297 mutex_ok:
298 am->vlib_rp = vlib_rp;
299 while (unix_shared_memory_queue_sub (q,
300 (u8 *) & old_msg,
301 1 /* nowait */ )
302 != -2 /* queue underflow */ )
303 {
304 vl_msg_api_free_nolock ((void *) old_msg);
305 am->shmem_hdr->restart_reclaims++;
306 }
307 pthread_mutex_unlock (&vlib_rp->mutex);
308 root_rp = svm_get_root_rp ();
309 ASSERT (root_rp);
310 /* Clean up the root region client list */
311 pthread_mutex_lock (&root_rp->mutex);
312 svm_client_scan_this_region_nolock (root_rp);
313 pthread_mutex_unlock (&root_rp->mutex);
314 }
315 else
316 {
317 pthread_mutex_unlock (&vlib_rp->mutex);
318 }
319 am->vlib_rp = vlib_rp;
320 vec_add1 (am->mapped_shmem_regions, vlib_rp);
321 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700322 }
Dave Barach371e4e12016-07-08 09:38:52 -0400323 /* Clients simply have to wait... */
324 if (!is_vlib)
325 {
326 pthread_mutex_unlock (&vlib_rp->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700327
Dave Barach371e4e12016-07-08 09:38:52 -0400328 /* Wait up to 100 seconds... */
329 for (i = 0; i < 10000; i++)
330 {
331 ts.tv_sec = 0;
332 ts.tv_nsec = 10000 * 1000; /* 10 ms */
333 while (nanosleep (&ts, &tsrem) < 0)
334 ts = tsrem;
335 if (vlib_rp->user_ctx)
336 goto ready;
337 }
338 /* Clean up and leave... */
339 svm_region_unmap (vlib_rp);
340 clib_warning ("region init fail");
341 return (-2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700342
343 ready:
Dave Barach371e4e12016-07-08 09:38:52 -0400344 am->shmem_hdr = (void *) vlib_rp->user_ctx;
345 am->our_pid = getpid ();
346 am->vlib_rp = vlib_rp;
347 vec_add1 (am->mapped_shmem_regions, vlib_rp);
348 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700349 }
350
Dave Barach371e4e12016-07-08 09:38:52 -0400351 /* Nope, it's our problem... */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352
Dave Barach371e4e12016-07-08 09:38:52 -0400353 oldheap = svm_push_data_heap (vlib_rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700354
Dave Barach371e4e12016-07-08 09:38:52 -0400355 vec_validate (shmem_hdr, 0);
356 shmem_hdr->version = VL_SHM_VERSION;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700357
Dave Barach371e4e12016-07-08 09:38:52 -0400358 /* vlib main input queue */
359 shmem_hdr->vl_input_queue =
360 unix_shared_memory_queue_init (1024, sizeof (uword), getpid (),
361 am->vlib_signal);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700362
Dave Barach371e4e12016-07-08 09:38:52 -0400363 /* Set up the msg ring allocator */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700364#define _(sz,n) \
365 do { \
366 ring_alloc_t _rp; \
367 _rp.rp = unix_shared_memory_queue_init ((n), (sz), 0, 0); \
368 _rp.size = (sz); \
369 _rp.nitems = n; \
370 _rp.hits = 0; \
371 _rp.misses = 0; \
372 vec_add1(shmem_hdr->vl_rings, _rp); \
373 } while (0);
374
Dave Barach371e4e12016-07-08 09:38:52 -0400375 foreach_vl_aring_size;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700376#undef _
377
378#define _(sz,n) \
379 do { \
380 ring_alloc_t _rp; \
381 _rp.rp = unix_shared_memory_queue_init ((n), (sz), 0, 0); \
382 _rp.size = (sz); \
383 _rp.nitems = n; \
384 _rp.hits = 0; \
385 _rp.misses = 0; \
386 vec_add1(shmem_hdr->client_rings, _rp); \
387 } while (0);
388
Dave Barach371e4e12016-07-08 09:38:52 -0400389 foreach_clnt_aring_size;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700390#undef _
391
Dave Barach371e4e12016-07-08 09:38:52 -0400392 am->shmem_hdr = shmem_hdr;
393 am->vlib_rp = vlib_rp;
394 am->our_pid = getpid ();
395 if (is_vlib)
396 am->shmem_hdr->vl_pid = am->our_pid;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700397
Dave Barach371e4e12016-07-08 09:38:52 -0400398 svm_pop_heap (oldheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700399
Dave Barach371e4e12016-07-08 09:38:52 -0400400 /*
401 * After absolutely everything that a client might see is set up,
402 * declare the shmem region valid
403 */
404 vlib_rp->user_ctx = shmem_hdr;
405
406 pthread_mutex_unlock (&vlib_rp->mutex);
407 vec_add1 (am->mapped_shmem_regions, vlib_rp);
408 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409}
410
Dave Barach371e4e12016-07-08 09:38:52 -0400411void
412vl_register_mapped_shmem_region (svm_region_t * rp)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700413{
Dave Barach371e4e12016-07-08 09:38:52 -0400414 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700415
Dave Barach371e4e12016-07-08 09:38:52 -0400416 vec_add1 (am->mapped_shmem_regions, rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700417}
418
Dave Barach371e4e12016-07-08 09:38:52 -0400419void
420vl_unmap_shmem (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700421{
Dave Barach371e4e12016-07-08 09:38:52 -0400422 svm_region_t *rp;
423 int i;
424 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700425
Dave Barach371e4e12016-07-08 09:38:52 -0400426 if (!svm_get_root_rp ())
427 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700428
Dave Barach371e4e12016-07-08 09:38:52 -0400429 for (i = 0; i < vec_len (am->mapped_shmem_regions); i++)
430 {
431 rp = am->mapped_shmem_regions[i];
432 svm_region_unmap (rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700433 }
434
Dave Barach371e4e12016-07-08 09:38:52 -0400435 vec_free (am->mapped_shmem_regions);
436 am->shmem_hdr = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700437
Dave Barach371e4e12016-07-08 09:38:52 -0400438 svm_region_exit ();
439 /* $$$ more careful cleanup, valgrind run... */
440 vec_free (am->msg_handlers);
441 vec_free (am->msg_endian_handlers);
442 vec_free (am->msg_print_handlers);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700443}
444
Dave Barach371e4e12016-07-08 09:38:52 -0400445void
446vl_msg_api_send_shmem (unix_shared_memory_queue_t * q, u8 * elem)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700447{
Dave Barach371e4e12016-07-08 09:38:52 -0400448 api_main_t *am = &api_main;
449 uword *trace = (uword *) elem;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700450
Dave Barach371e4e12016-07-08 09:38:52 -0400451 if (am->tx_trace && am->tx_trace->enabled)
452 vl_msg_api_trace (am, am->tx_trace, (void *) trace[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700453
Dave Barach371e4e12016-07-08 09:38:52 -0400454 (void) unix_shared_memory_queue_add (q, elem, 0 /* nowait */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700455}
456
Dave Barach371e4e12016-07-08 09:38:52 -0400457void
458vl_msg_api_send_shmem_nolock (unix_shared_memory_queue_t * q, u8 * elem)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700459{
Dave Barach371e4e12016-07-08 09:38:52 -0400460 api_main_t *am = &api_main;
461 uword *trace = (uword *) elem;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700462
Dave Barach371e4e12016-07-08 09:38:52 -0400463 if (am->tx_trace && am->tx_trace->enabled)
464 vl_msg_api_trace (am, am->tx_trace, (void *) trace[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700465
Dave Barach371e4e12016-07-08 09:38:52 -0400466 (void) unix_shared_memory_queue_add_nolock (q, elem);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700467}
468
Dave Barach371e4e12016-07-08 09:38:52 -0400469static void
470vl_api_memclnt_create_reply_t_handler (vl_api_memclnt_create_reply_t * mp)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700471{
Dave Barach371e4e12016-07-08 09:38:52 -0400472 api_main_t *am = &api_main;
473 int rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700474
Dave Barach371e4e12016-07-08 09:38:52 -0400475 am->my_client_index = mp->index;
476 am->my_registration = (vl_api_registration_t *) (uword) mp->handle;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700477
Dave Barach371e4e12016-07-08 09:38:52 -0400478 rv = ntohl (mp->response);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700479
Dave Barach371e4e12016-07-08 09:38:52 -0400480 if (rv < 0)
481 clib_warning ("WARNING: API mismatch detected");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700482}
483
Dave Barach371e4e12016-07-08 09:38:52 -0400484void vl_client_add_api_signatures (vl_api_memclnt_create_t * mp)
485 __attribute__ ((weak));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700486
Dave Barach371e4e12016-07-08 09:38:52 -0400487void
488vl_client_add_api_signatures (vl_api_memclnt_create_t * mp)
489{
490 int i;
491
492 for (i = 0; i < ARRAY_LEN (mp->api_versions); i++)
493 mp->api_versions[i] = 0;
494}
495
496int
497vl_client_connect (char *name, int ctx_quota, int input_queue_size)
498{
499 svm_region_t *svm;
500 vl_api_memclnt_create_t *mp;
501 vl_api_memclnt_create_reply_t *rp;
502 unix_shared_memory_queue_t *vl_input_queue;
503 vl_shmem_hdr_t *shmem_hdr;
504 int rv = 0;
505 void *oldheap;
506 api_main_t *am = &api_main;
507
508 if (am->my_registration)
509 {
510 clib_warning ("client %s already connected...", name);
511 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700512 }
513
Dave Barach371e4e12016-07-08 09:38:52 -0400514 if (am->vlib_rp == 0)
515 {
516 clib_warning ("am->vlib_rp NULL");
517 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700518 }
519
Dave Barach371e4e12016-07-08 09:38:52 -0400520 svm = am->vlib_rp;
521 shmem_hdr = am->shmem_hdr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700522
Dave Barach371e4e12016-07-08 09:38:52 -0400523 if (shmem_hdr == 0 || shmem_hdr->vl_input_queue == 0)
524 {
525 clib_warning ("shmem_hdr / input queue NULL");
526 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700527 }
528
Dave Barach371e4e12016-07-08 09:38:52 -0400529 pthread_mutex_lock (&svm->mutex);
530 oldheap = svm_push_data_heap (svm);
531 vl_input_queue =
532 unix_shared_memory_queue_init (input_queue_size, sizeof (uword),
533 getpid (), 0);
534 pthread_mutex_unlock (&svm->mutex);
535 svm_pop_heap (oldheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700536
Dave Barach371e4e12016-07-08 09:38:52 -0400537 am->my_client_index = ~0;
538 am->my_registration = 0;
539 am->vl_input_queue = vl_input_queue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700540
Dave Barach371e4e12016-07-08 09:38:52 -0400541 mp = vl_msg_api_alloc (sizeof (vl_api_memclnt_create_t));
542 memset (mp, 0, sizeof (*mp));
543 mp->_vl_msg_id = ntohs (VL_API_MEMCLNT_CREATE);
544 mp->ctx_quota = ctx_quota;
545 mp->input_queue = (uword) vl_input_queue;
546 strncpy ((char *) mp->name, name, sizeof (mp->name) - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700547
Dave Barach371e4e12016-07-08 09:38:52 -0400548 vl_client_add_api_signatures (mp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700549
Dave Barach371e4e12016-07-08 09:38:52 -0400550 vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) & mp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700551
Dave Barach371e4e12016-07-08 09:38:52 -0400552 while (1)
553 {
554 int qstatus;
555 struct timespec ts, tsrem;
556 int i;
557
558 /* Wait up to 10 seconds */
559 for (i = 0; i < 1000; i++)
560 {
561 qstatus = unix_shared_memory_queue_sub (vl_input_queue, (u8 *) & rp,
562 1 /* nowait */ );
563 if (qstatus == 0)
564 goto read_one_msg;
565 ts.tv_sec = 0;
566 ts.tv_nsec = 10000 * 1000; /* 10 ms */
567 while (nanosleep (&ts, &tsrem) < 0)
568 ts = tsrem;
569 }
570 /* Timeout... */
571 clib_warning ("memclnt_create_reply timeout");
572 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700573
574 read_one_msg:
Dave Barach371e4e12016-07-08 09:38:52 -0400575 if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_CREATE_REPLY)
576 {
577 clib_warning ("unexpected reply: id %d", ntohs (rp->_vl_msg_id));
578 continue;
579 }
580 rv = clib_net_to_host_u32 (rp->response);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700581
Dave Barach371e4e12016-07-08 09:38:52 -0400582 vl_msg_api_handler ((void *) rp);
583 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700584 }
Dave Barach371e4e12016-07-08 09:38:52 -0400585 return (rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700586}
587
Dave Barach371e4e12016-07-08 09:38:52 -0400588static void
589vl_api_memclnt_delete_reply_t_handler (vl_api_memclnt_delete_reply_t * mp)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700590{
Dave Barach371e4e12016-07-08 09:38:52 -0400591 void *oldheap;
592 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700593
Dave Barach371e4e12016-07-08 09:38:52 -0400594 pthread_mutex_lock (&am->vlib_rp->mutex);
595 oldheap = svm_push_data_heap (am->vlib_rp);
596 unix_shared_memory_queue_free (am->vl_input_queue);
597 pthread_mutex_unlock (&am->vlib_rp->mutex);
598 svm_pop_heap (oldheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700599
Dave Barach371e4e12016-07-08 09:38:52 -0400600 am->my_client_index = ~0;
601 am->my_registration = 0;
602 am->vl_input_queue = 0;
603}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700604
Dave Barach371e4e12016-07-08 09:38:52 -0400605void
606vl_client_disconnect (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700607{
Dave Barach371e4e12016-07-08 09:38:52 -0400608 vl_api_memclnt_delete_t *mp;
609 vl_api_memclnt_delete_reply_t *rp;
610 unix_shared_memory_queue_t *vl_input_queue;
611 vl_shmem_hdr_t *shmem_hdr;
612 time_t begin;
613 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700614
Dave Barach371e4e12016-07-08 09:38:52 -0400615 ASSERT (am->vlib_rp);
616 shmem_hdr = am->shmem_hdr;
617 ASSERT (shmem_hdr && shmem_hdr->vl_input_queue);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700618
Dave Barach371e4e12016-07-08 09:38:52 -0400619 vl_input_queue = am->vl_input_queue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700620
Dave Barach371e4e12016-07-08 09:38:52 -0400621 mp = vl_msg_api_alloc (sizeof (vl_api_memclnt_delete_t));
622 memset (mp, 0, sizeof (*mp));
623 mp->_vl_msg_id = ntohs (VL_API_MEMCLNT_DELETE);
624 mp->index = am->my_client_index;
625 mp->handle = (uword) am->my_registration;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700626
Dave Barach371e4e12016-07-08 09:38:52 -0400627 vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) & mp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700628
Dave Barach371e4e12016-07-08 09:38:52 -0400629 /*
630 * Have to be careful here, in case the client is disconnecting
631 * because e.g. the vlib process died, or is unresponsive.
632 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700633
Dave Barach371e4e12016-07-08 09:38:52 -0400634 begin = time (0);
635 while (1)
636 {
637 time_t now;
638
639 now = time (0);
640
641 if (now >= (begin + 2))
642 {
643 clib_warning ("peer unresponsive, give up");
644 am->my_client_index = ~0;
645 am->my_registration = 0;
646 am->shmem_hdr = 0;
647 break;
648 }
649 if (unix_shared_memory_queue_sub (vl_input_queue, (u8 *) & rp, 1) < 0)
650 continue;
651
652 /* drain the queue */
653 if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
654 {
655 vl_msg_api_handler ((void *) rp);
656 continue;
657 }
658 vl_msg_api_handler ((void *) rp);
659 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700660 }
661}
662
Dave Barach371e4e12016-07-08 09:38:52 -0400663static inline vl_api_registration_t *
664vl_api_client_index_to_registration_internal (u32 handle)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700665{
Dave Barach371e4e12016-07-08 09:38:52 -0400666 vl_api_registration_t **regpp;
667 vl_api_registration_t *regp;
668 api_main_t *am = &api_main;
669 u32 index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700670
Dave Barach371e4e12016-07-08 09:38:52 -0400671 index = vl_msg_api_handle_get_index (handle);
672 if ((am->shmem_hdr->application_restarts & VL_API_EPOCH_MASK)
673 != vl_msg_api_handle_get_epoch (handle))
674 {
675 vl_msg_api_increment_missing_client_counter ();
676 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700677 }
678
Dave Barach371e4e12016-07-08 09:38:52 -0400679 regpp = am->vl_clients + index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700680
Dave Barach371e4e12016-07-08 09:38:52 -0400681 if (pool_is_free (am->vl_clients, regpp))
682 {
683 vl_msg_api_increment_missing_client_counter ();
684 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700685 }
Dave Barach371e4e12016-07-08 09:38:52 -0400686 regp = *regpp;
687 return (regp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700688}
689
Dave Barach371e4e12016-07-08 09:38:52 -0400690vl_api_registration_t *
691vl_api_client_index_to_registration (u32 index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700692{
Dave Barach371e4e12016-07-08 09:38:52 -0400693 return (vl_api_client_index_to_registration_internal (index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700694}
695
Dave Barach371e4e12016-07-08 09:38:52 -0400696unix_shared_memory_queue_t *
697vl_api_client_index_to_input_queue (u32 index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700698{
Dave Barach371e4e12016-07-08 09:38:52 -0400699 vl_api_registration_t *regp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700700
Dave Barach371e4e12016-07-08 09:38:52 -0400701 regp = vl_api_client_index_to_registration_internal (index);
702 if (!regp)
703 return 0;
704 return (regp->vl_input_queue);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700705}
706
707#define foreach_api_client_msg \
708_(MEMCLNT_CREATE_REPLY, memclnt_create_reply) \
709_(MEMCLNT_DELETE_REPLY, memclnt_delete_reply)
710
Dave Barach371e4e12016-07-08 09:38:52 -0400711int
712vl_client_api_map (char *region_name)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700713{
Dave Barach371e4e12016-07-08 09:38:52 -0400714 int rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700715
Dave Barach371e4e12016-07-08 09:38:52 -0400716 if ((rv = vl_map_shmem (region_name, 0 /* is_vlib */ )) < 0)
717 {
718 return rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700719 }
720
721#define _(N,n) \
722 vl_msg_api_set_handlers(VL_API_##N, 0 /* name */, \
723 vl_api_##n##_t_handler, \
724 0/* cleanup */, 0/* endian */, 0/* print */, \
Dave Barach371e4e12016-07-08 09:38:52 -0400725 sizeof(vl_api_##n##_t), 1);
726 foreach_api_client_msg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700727#undef _
Dave Barach371e4e12016-07-08 09:38:52 -0400728 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700729}
730
Dave Barach371e4e12016-07-08 09:38:52 -0400731void
732vl_client_api_unmap (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700733{
Dave Barach371e4e12016-07-08 09:38:52 -0400734 vl_unmap_shmem ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700735}
Dave Barach371e4e12016-07-08 09:38:52 -0400736
737/*
738 * fd.io coding-style-patch-verification: ON
739 *
740 * Local Variables:
741 * eval: (c-set-style "gnu")
742 * End:
743 */