blob: 0a3c23cbb3edde396cd41c39a2a2ed1f51d261a6 [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 Barach59b25652017-09-10 15:04:27 -040042socket_main_t socket_main;
43
44#define DEBUG_MESSAGE_BUFFER_OVERRUN 0
45
Dave Barach371e4e12016-07-08 09:38:52 -040046static inline void *
Dave Barach77378332016-10-13 17:35:09 -040047vl_msg_api_alloc_internal (int nbytes, int pool, int may_return_null)
Ed Warnickecb9cada2015-12-08 15:45:58 -070048{
Dave Barach371e4e12016-07-08 09:38:52 -040049 int i;
50 msgbuf_t *rv;
51 ring_alloc_t *ap;
52 unix_shared_memory_queue_t *q;
53 void *oldheap;
54 vl_shmem_hdr_t *shmem_hdr;
55 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -070056
Dave Barach371e4e12016-07-08 09:38:52 -040057 shmem_hdr = am->shmem_hdr;
Ed Warnickecb9cada2015-12-08 15:45:58 -070058
Dave Barach59b25652017-09-10 15:04:27 -040059#if DEBUG_MESSAGE_BUFFER_OVERRUN > 0
60 nbytes += 4;
61#endif
62
Florin Coras7a2e1bd2017-11-30 16:07:39 -050063 ASSERT (pool == 0 || vlib_get_thread_index () == 0);
64
Dave Barach371e4e12016-07-08 09:38:52 -040065 if (shmem_hdr == 0)
66 {
67 clib_warning ("shared memory header NULL");
68 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -070069 }
70
Dave Barach371e4e12016-07-08 09:38:52 -040071 /* account for the msgbuf_t header */
72 nbytes += sizeof (msgbuf_t);
Ed Warnickecb9cada2015-12-08 15:45:58 -070073
Dave Barach371e4e12016-07-08 09:38:52 -040074 if (shmem_hdr->vl_rings == 0)
75 {
76 clib_warning ("vl_rings NULL");
Dave Barach77378332016-10-13 17:35:09 -040077 ASSERT (0);
78 abort ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070079 }
80
Dave Barach371e4e12016-07-08 09:38:52 -040081 if (shmem_hdr->client_rings == 0)
82 {
83 clib_warning ("client_rings NULL");
Dave Barach77378332016-10-13 17:35:09 -040084 ASSERT (0);
85 abort ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070086 }
87
Dave Barach371e4e12016-07-08 09:38:52 -040088 ap = pool ? shmem_hdr->vl_rings : shmem_hdr->client_rings;
89 for (i = 0; i < vec_len (ap); i++)
90 {
91 /* Too big? */
92 if (nbytes > ap[i].size)
93 {
94 continue;
95 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070096
Dave Barach371e4e12016-07-08 09:38:52 -040097 q = ap[i].rp;
98 if (pool == 0)
99 {
100 pthread_mutex_lock (&q->mutex);
101 }
102 rv = (msgbuf_t *) (&q->data[0] + q->head * q->elsize);
103 /*
104 * Is this item still in use?
105 */
106 if (rv->q)
107 {
Dave Barach842b9c52017-01-09 15:54:00 -0500108 u32 now = (u32) time (0);
109
110 if (PREDICT_TRUE (rv->gc_mark_timestamp == 0))
111 rv->gc_mark_timestamp = now;
112 else
113 {
114 if (now - rv->gc_mark_timestamp > 10)
115 {
116 if (CLIB_DEBUG > 0)
Dave Barach10d8cc62017-05-30 09:30:07 -0400117 {
118 u16 *msg_idp, msg_id;
119 clib_warning
120 ("garbage collect pool %d ring %d index %d", pool, i,
121 q->head);
122 msg_idp = (u16 *) (rv->data);
123 msg_id = clib_net_to_host_u16 (*msg_idp);
124 if (msg_id < vec_len (api_main.msg_names))
125 clib_warning ("msg id %d name %s", (u32) msg_id,
126 api_main.msg_names[msg_id]);
127 }
Dave Barach842b9c52017-01-09 15:54:00 -0500128 shmem_hdr->garbage_collects++;
129 goto collected;
130 }
131 }
132
133
Dave Barach371e4e12016-07-08 09:38:52 -0400134 /* yes, loser; try next larger pool */
135 ap[i].misses++;
136 if (pool == 0)
137 pthread_mutex_unlock (&q->mutex);
138 continue;
139 }
Dave Barach842b9c52017-01-09 15:54:00 -0500140 collected:
141
Dave Barach371e4e12016-07-08 09:38:52 -0400142 /* OK, we have a winner */
143 ap[i].hits++;
144 /*
145 * Remember the source queue, although we
146 * don't need to know the queue to free the item.
147 */
148 rv->q = q;
Dave Barach842b9c52017-01-09 15:54:00 -0500149 rv->gc_mark_timestamp = 0;
Dave Barach371e4e12016-07-08 09:38:52 -0400150 q->head++;
151 if (q->head == q->maxsize)
152 q->head = 0;
153
154 if (pool == 0)
155 pthread_mutex_unlock (&q->mutex);
156 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700157 }
158
Dave Barach371e4e12016-07-08 09:38:52 -0400159 /*
160 * Request too big, or head element of all size-compatible rings
161 * still in use. Fall back to shared-memory malloc.
162 */
163 am->ring_misses++;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164
Dave Barach371e4e12016-07-08 09:38:52 -0400165 pthread_mutex_lock (&am->vlib_rp->mutex);
166 oldheap = svm_push_data_heap (am->vlib_rp);
Dave Barach77378332016-10-13 17:35:09 -0400167 if (may_return_null)
168 {
169 rv = clib_mem_alloc_or_null (nbytes);
170 if (PREDICT_FALSE (rv == 0))
171 {
172 svm_pop_heap (oldheap);
173 pthread_mutex_unlock (&am->vlib_rp->mutex);
174 return 0;
175 }
176 }
177 else
178 rv = clib_mem_alloc (nbytes);
179
Dave Barach371e4e12016-07-08 09:38:52 -0400180 rv->q = 0;
181 svm_pop_heap (oldheap);
182 pthread_mutex_unlock (&am->vlib_rp->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700183
Dave Barach371e4e12016-07-08 09:38:52 -0400184out:
Dave Barach59b25652017-09-10 15:04:27 -0400185#if DEBUG_MESSAGE_BUFFER_OVERRUN > 0
186 {
187 nbytes -= 4;
188 u32 *overrun;
189 overrun = (u32 *) (rv->data + nbytes - sizeof (msgbuf_t));
190 *overrun = 0x1badbabe;
191 }
192#endif
Dave Barach371e4e12016-07-08 09:38:52 -0400193 rv->data_len = htonl (nbytes - sizeof (msgbuf_t));
Dave Barach59b25652017-09-10 15:04:27 -0400194
Dave Barach371e4e12016-07-08 09:38:52 -0400195 return (rv->data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700196}
197
Dave Barach371e4e12016-07-08 09:38:52 -0400198void *
199vl_msg_api_alloc (int nbytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200{
Dave Barach371e4e12016-07-08 09:38:52 -0400201 int pool;
202 api_main_t *am = &api_main;
203 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204
Dave Barach371e4e12016-07-08 09:38:52 -0400205 /*
206 * Clients use pool-0, vlib proc uses pool 1
207 */
208 pool = (am->our_pid == shmem_hdr->vl_pid);
Dave Barach77378332016-10-13 17:35:09 -0400209 return vl_msg_api_alloc_internal (nbytes, pool, 0 /* may_return_null */ );
210}
211
212void *
213vl_msg_api_alloc_or_null (int nbytes)
214{
215 int pool;
216 api_main_t *am = &api_main;
217 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
218
219 pool = (am->our_pid == shmem_hdr->vl_pid);
220 return vl_msg_api_alloc_internal (nbytes, pool, 1 /* may_return_null */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221}
222
Dave Barach371e4e12016-07-08 09:38:52 -0400223void *
224vl_msg_api_alloc_as_if_client (int nbytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225{
Dave Barach77378332016-10-13 17:35:09 -0400226 return vl_msg_api_alloc_internal (nbytes, 0, 0 /* may_return_null */ );
227}
228
229void *
230vl_msg_api_alloc_as_if_client_or_null (int nbytes)
231{
232 return vl_msg_api_alloc_internal (nbytes, 0, 1 /* may_return_null */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233}
234
Dave Barach371e4e12016-07-08 09:38:52 -0400235void
236vl_msg_api_free (void *a)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700237{
Dave Barach371e4e12016-07-08 09:38:52 -0400238 msgbuf_t *rv;
239 void *oldheap;
240 api_main_t *am = &api_main;
Ole Troan6855f6c2016-04-09 03:16:30 +0200241
Dave Barach371e4e12016-07-08 09:38:52 -0400242 rv = (msgbuf_t *) (((u8 *) a) - offsetof (msgbuf_t, data));
243
244 /*
245 * Here's the beauty of the scheme. Only one proc/thread has
246 * control of a given message buffer. To free a buffer, we just clear the
247 * queue field, and leave. No locks, no hits, no errors...
248 */
249 if (rv->q)
250 {
251 rv->q = 0;
Dave Barach842b9c52017-01-09 15:54:00 -0500252 rv->gc_mark_timestamp = 0;
Dave Barach59b25652017-09-10 15:04:27 -0400253#if DEBUG_MESSAGE_BUFFER_OVERRUN > 0
254 {
255 u32 *overrun;
256 overrun = (u32 *) (rv->data + ntohl (rv->data_len));
257 ASSERT (*overrun == 0x1badbabe);
258 }
259#endif
Dave Barach371e4e12016-07-08 09:38:52 -0400260 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261 }
262
Dave Barach371e4e12016-07-08 09:38:52 -0400263 pthread_mutex_lock (&am->vlib_rp->mutex);
264 oldheap = svm_push_data_heap (am->vlib_rp);
Dave Barach59b25652017-09-10 15:04:27 -0400265
266#if DEBUG_MESSAGE_BUFFER_OVERRUN > 0
267 {
268 u32 *overrun;
269 overrun = (u32 *) (rv->data + ntohl (rv->data_len));
270 ASSERT (*overrun == 0x1badbabe);
271 }
272#endif
273
Dave Barach371e4e12016-07-08 09:38:52 -0400274 clib_mem_free (rv);
275 svm_pop_heap (oldheap);
276 pthread_mutex_unlock (&am->vlib_rp->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700277}
278
Dave Barach371e4e12016-07-08 09:38:52 -0400279static void
280vl_msg_api_free_nolock (void *a)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700281{
Dave Barach371e4e12016-07-08 09:38:52 -0400282 msgbuf_t *rv;
283 void *oldheap;
284 api_main_t *am = &api_main;
285
286 rv = (msgbuf_t *) (((u8 *) a) - offsetof (msgbuf_t, data));
287 /*
288 * Here's the beauty of the scheme. Only one proc/thread has
289 * control of a given message buffer. To free a buffer, we just clear the
290 * queue field, and leave. No locks, no hits, no errors...
291 */
292 if (rv->q)
293 {
294 rv->q = 0;
295 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700296 }
297
Dave Barach371e4e12016-07-08 09:38:52 -0400298 oldheap = svm_push_data_heap (am->vlib_rp);
299 clib_mem_free (rv);
300 svm_pop_heap (oldheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700301}
302
Dave Barach371e4e12016-07-08 09:38:52 -0400303void
Neale Rannse72be392017-04-26 13:59:20 -0700304vl_set_memory_root_path (const char *name)
Dave Barach309bef22016-01-22 16:09:52 -0500305{
Dave Barach371e4e12016-07-08 09:38:52 -0400306 api_main_t *am = &api_main;
Dave Barach309bef22016-01-22 16:09:52 -0500307
Dave Barach371e4e12016-07-08 09:38:52 -0400308 am->root_path = name;
Dave Barach309bef22016-01-22 16:09:52 -0500309}
310
Dave Barach371e4e12016-07-08 09:38:52 -0400311void
312vl_set_memory_uid (int uid)
Dave Barach16c75df2016-05-31 14:05:46 -0400313{
Dave Barach371e4e12016-07-08 09:38:52 -0400314 api_main_t *am = &api_main;
Dave Barach16c75df2016-05-31 14:05:46 -0400315
Dave Barach371e4e12016-07-08 09:38:52 -0400316 am->api_uid = uid;
Dave Barach16c75df2016-05-31 14:05:46 -0400317}
318
Dave Barach371e4e12016-07-08 09:38:52 -0400319void
320vl_set_memory_gid (int gid)
Dave Barach16c75df2016-05-31 14:05:46 -0400321{
Dave Barach371e4e12016-07-08 09:38:52 -0400322 api_main_t *am = &api_main;
Dave Barach16c75df2016-05-31 14:05:46 -0400323
Dave Barach371e4e12016-07-08 09:38:52 -0400324 am->api_gid = gid;
Dave Barach16c75df2016-05-31 14:05:46 -0400325}
326
Dave Barachb3d93da2016-08-03 14:34:38 -0400327void
328vl_set_global_memory_baseva (u64 baseva)
329{
330 api_main_t *am = &api_main;
331
332 am->global_baseva = baseva;
333}
334
335void
336vl_set_global_memory_size (u64 size)
337{
338 api_main_t *am = &api_main;
339
340 am->global_size = size;
341}
342
343void
344vl_set_api_memory_size (u64 size)
345{
346 api_main_t *am = &api_main;
347
348 am->api_size = size;
349}
350
351void
352vl_set_global_pvt_heap_size (u64 size)
353{
354 api_main_t *am = &api_main;
355
356 am->global_pvt_heap_size = size;
357}
358
359void
360vl_set_api_pvt_heap_size (u64 size)
361{
362 api_main_t *am = &api_main;
363
364 am->api_pvt_heap_size = size;
365}
366
Florin Coras90a63982017-12-19 04:50:01 -0800367static void
368vl_api_default_mem_config (vl_shmem_hdr_t * shmem_hdr)
Dave Barach59b25652017-09-10 15:04:27 -0400369{
370 api_main_t *am = &api_main;
Dave Barach59b25652017-09-10 15:04:27 -0400371 u32 vlib_input_queue_length;
Dave Barach59b25652017-09-10 15:04:27 -0400372
373 /* vlib main input queue */
374 vlib_input_queue_length = 1024;
375 if (am->vlib_input_queue_length)
376 vlib_input_queue_length = am->vlib_input_queue_length;
377
378 shmem_hdr->vl_input_queue =
379 unix_shared_memory_queue_init (vlib_input_queue_length, sizeof (uword),
380 getpid (), am->vlib_signal);
381
Dave Barach59b25652017-09-10 15:04:27 -0400382#define _(sz,n) \
383 do { \
384 ring_alloc_t _rp; \
385 _rp.rp = unix_shared_memory_queue_init ((n), (sz), 0, 0); \
386 _rp.size = (sz); \
387 _rp.nitems = n; \
388 _rp.hits = 0; \
389 _rp.misses = 0; \
390 vec_add1(shmem_hdr->vl_rings, _rp); \
391 } while (0);
392
393 foreach_vl_aring_size;
394#undef _
395
396#define _(sz,n) \
397 do { \
398 ring_alloc_t _rp; \
399 _rp.rp = unix_shared_memory_queue_init ((n), (sz), 0, 0); \
400 _rp.size = (sz); \
401 _rp.nitems = n; \
402 _rp.hits = 0; \
403 _rp.misses = 0; \
404 vec_add1(shmem_hdr->client_rings, _rp); \
405 } while (0);
406
407 foreach_clnt_aring_size;
408#undef _
Florin Coras90a63982017-12-19 04:50:01 -0800409}
410
411void
412vl_api_mem_config (vl_shmem_hdr_t * hdr, vl_api_shm_elem_config_t * config)
413{
414 api_main_t *am = &api_main;
415 vl_api_shm_elem_config_t *c;
416 ring_alloc_t *rp;
417 u32 size;
418
419 if (!config)
420 {
421 vl_api_default_mem_config (hdr);
422 return;
423 }
424
425 vec_foreach (c, config)
426 {
427 switch (c->type)
428 {
429 case VL_API_QUEUE:
430 hdr->vl_input_queue = unix_shared_memory_queue_init (c->count,
431 c->size,
432 getpid (),
433 am->vlib_signal);
434 continue;
435 case VL_API_VLIB_RING:
436 vec_add2 (hdr->vl_rings, rp, 1);
437 break;
438 case VL_API_CLIENT_RING:
439 vec_add2 (hdr->client_rings, rp, 1);
440 break;
441 default:
442 clib_warning ("unknown config type: %d", c->type);
443 continue;
444 }
445
446 size = sizeof (ring_alloc_t) + c->size;
447 rp->rp = unix_shared_memory_queue_init (c->count, size, 0, 0);
448 rp->size = size;
449 rp->nitems = c->count;
450 rp->hits = 0;
451 rp->misses = 0;
452 }
453}
454
455void
456vl_init_shmem (svm_region_t * vlib_rp, vl_api_shm_elem_config_t * config,
457 int is_vlib, int is_private_region)
458{
459 api_main_t *am = &api_main;
460 vl_shmem_hdr_t *shmem_hdr = 0;
461 void *oldheap;
462 ASSERT (vlib_rp);
463
464 /* $$$$ need private region config parameters */
465
466 oldheap = svm_push_data_heap (vlib_rp);
467
468 vec_validate (shmem_hdr, 0);
469 shmem_hdr->version = VL_SHM_VERSION;
470
471 /* Set up the queue and msg ring allocator */
472 vl_api_mem_config (shmem_hdr, config);
Dave Barach59b25652017-09-10 15:04:27 -0400473
474 if (is_private_region == 0)
475 {
476 am->shmem_hdr = shmem_hdr;
477 am->vlib_rp = vlib_rp;
478 am->our_pid = getpid ();
479 if (is_vlib)
480 am->shmem_hdr->vl_pid = am->our_pid;
481 }
482 else
483 shmem_hdr->vl_pid = am->our_pid;
484
485 svm_pop_heap (oldheap);
486
487 /*
488 * After absolutely everything that a client might see is set up,
489 * declare the shmem region valid
490 */
491 vlib_rp->user_ctx = shmem_hdr;
492
493 pthread_mutex_unlock (&vlib_rp->mutex);
494}
495
496
Dave Barach371e4e12016-07-08 09:38:52 -0400497int
Neale Rannse72be392017-04-26 13:59:20 -0700498vl_map_shmem (const char *region_name, int is_vlib)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700499{
Dave Barach371e4e12016-07-08 09:38:52 -0400500 svm_map_region_args_t _a, *a = &_a;
501 svm_region_t *vlib_rp, *root_rp;
Dave Barach371e4e12016-07-08 09:38:52 -0400502 api_main_t *am = &api_main;
Ole Troan3cdc25f2017-08-17 11:07:33 +0200503 int i, rv;
Dave Barach371e4e12016-07-08 09:38:52 -0400504 struct timespec ts, tsrem;
Dave Wallacecfc997e2017-08-22 18:32:34 -0400505 char *vpe_api_region_suffix = "-vpe-api";
Ed Warnickecb9cada2015-12-08 15:45:58 -0700506
Jan Srnicek5beec812017-03-24 10:18:11 +0100507 memset (a, 0, sizeof (*a));
508
Dave Wallacecfc997e2017-08-22 18:32:34 -0400509 if (strstr (region_name, vpe_api_region_suffix))
Jan Srnicek5beec812017-03-24 10:18:11 +0100510 {
Dave Wallacecfc997e2017-08-22 18:32:34 -0400511 u8 *root_path = format (0, "%s", region_name);
512 _vec_len (root_path) = (vec_len (root_path) -
513 strlen (vpe_api_region_suffix));
514 vec_terminate_c_string (root_path);
515 a->root_path = (const char *) root_path;
516 am->root_path = (const char *) root_path;
Jan Srnicek5beec812017-03-24 10:18:11 +0100517 }
518
Dave Barach371e4e12016-07-08 09:38:52 -0400519 if (is_vlib == 0)
Ole Troan3cdc25f2017-08-17 11:07:33 +0200520 {
521 rv = svm_region_init_chroot (am->root_path);
522 if (rv)
523 return rv;
524 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700525
Jan Srnicek5beec812017-03-24 10:18:11 +0100526 if (a->root_path != NULL)
527 {
528 a->name = "/vpe-api";
529 }
530 else
531 a->name = region_name;
Dave Barachc3799992016-08-15 11:12:27 -0400532 a->size = am->api_size ? am->api_size : (16 << 20);
Dave Barach371e4e12016-07-08 09:38:52 -0400533 a->flags = SVM_FLAGS_MHEAP;
534 a->uid = am->api_uid;
535 a->gid = am->api_gid;
Dave Barachb3d93da2016-08-03 14:34:38 -0400536 a->pvt_heap_size = am->api_pvt_heap_size;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700537
Dave Barach371e4e12016-07-08 09:38:52 -0400538 vlib_rp = svm_region_find_or_create (a);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700539
Dave Barach371e4e12016-07-08 09:38:52 -0400540 if (vlib_rp == 0)
541 return (-2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700542
Dave Barach371e4e12016-07-08 09:38:52 -0400543 pthread_mutex_lock (&vlib_rp->mutex);
544 /* Has someone else set up the shared-memory variable table? */
545 if (vlib_rp->user_ctx)
546 {
547 am->shmem_hdr = (void *) vlib_rp->user_ctx;
548 am->our_pid = getpid ();
549 if (is_vlib)
550 {
551 unix_shared_memory_queue_t *q;
552 uword old_msg;
553 /*
554 * application restart. Reset cached pids, API message
555 * rings, list of clients; otherwise, various things
556 * fail. (e.g. queue non-empty notification)
557 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700558
Dave Barach371e4e12016-07-08 09:38:52 -0400559 /* ghosts keep the region from disappearing properly */
560 svm_client_scan_this_region_nolock (vlib_rp);
561 am->shmem_hdr->application_restarts++;
562 q = am->shmem_hdr->vl_input_queue;
563 am->shmem_hdr->vl_pid = getpid ();
564 q->consumer_pid = am->shmem_hdr->vl_pid;
565 /* Drain the input queue, freeing msgs */
566 for (i = 0; i < 10; i++)
567 {
568 if (pthread_mutex_trylock (&q->mutex) == 0)
569 {
570 pthread_mutex_unlock (&q->mutex);
571 goto mutex_ok;
572 }
573 ts.tv_sec = 0;
574 ts.tv_nsec = 10000 * 1000; /* 10 ms */
575 while (nanosleep (&ts, &tsrem) < 0)
576 ts = tsrem;
577 }
578 /* Mutex buggered, "fix" it */
579 memset (&q->mutex, 0, sizeof (q->mutex));
580 clib_warning ("forcibly release main input queue mutex");
581
582 mutex_ok:
583 am->vlib_rp = vlib_rp;
584 while (unix_shared_memory_queue_sub (q,
585 (u8 *) & old_msg,
586 1 /* nowait */ )
587 != -2 /* queue underflow */ )
588 {
589 vl_msg_api_free_nolock ((void *) old_msg);
590 am->shmem_hdr->restart_reclaims++;
591 }
592 pthread_mutex_unlock (&vlib_rp->mutex);
593 root_rp = svm_get_root_rp ();
594 ASSERT (root_rp);
595 /* Clean up the root region client list */
596 pthread_mutex_lock (&root_rp->mutex);
597 svm_client_scan_this_region_nolock (root_rp);
598 pthread_mutex_unlock (&root_rp->mutex);
599 }
600 else
601 {
602 pthread_mutex_unlock (&vlib_rp->mutex);
603 }
604 am->vlib_rp = vlib_rp;
605 vec_add1 (am->mapped_shmem_regions, vlib_rp);
606 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700607 }
Dave Barach371e4e12016-07-08 09:38:52 -0400608 /* Clients simply have to wait... */
609 if (!is_vlib)
610 {
611 pthread_mutex_unlock (&vlib_rp->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700612
Dave Barach371e4e12016-07-08 09:38:52 -0400613 /* Wait up to 100 seconds... */
614 for (i = 0; i < 10000; i++)
615 {
616 ts.tv_sec = 0;
617 ts.tv_nsec = 10000 * 1000; /* 10 ms */
618 while (nanosleep (&ts, &tsrem) < 0)
619 ts = tsrem;
620 if (vlib_rp->user_ctx)
621 goto ready;
622 }
623 /* Clean up and leave... */
624 svm_region_unmap (vlib_rp);
625 clib_warning ("region init fail");
626 return (-2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700627
628 ready:
Dave Barach371e4e12016-07-08 09:38:52 -0400629 am->shmem_hdr = (void *) vlib_rp->user_ctx;
630 am->our_pid = getpid ();
631 am->vlib_rp = vlib_rp;
632 vec_add1 (am->mapped_shmem_regions, vlib_rp);
633 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700634 }
635
Dave Barach371e4e12016-07-08 09:38:52 -0400636 /* Nope, it's our problem... */
Florin Coras90a63982017-12-19 04:50:01 -0800637 vl_init_shmem (vlib_rp, 0 /* default config */ , 1 /* is vlib */ ,
638 0 /* is_private_region */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700639
Dave Barach371e4e12016-07-08 09:38:52 -0400640 vec_add1 (am->mapped_shmem_regions, vlib_rp);
641 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700642}
643
Dave Barach371e4e12016-07-08 09:38:52 -0400644void
645vl_register_mapped_shmem_region (svm_region_t * rp)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700646{
Dave Barach371e4e12016-07-08 09:38:52 -0400647 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700648
Dave Barach371e4e12016-07-08 09:38:52 -0400649 vec_add1 (am->mapped_shmem_regions, rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700650}
651
Dave Barach371e4e12016-07-08 09:38:52 -0400652void
653vl_unmap_shmem (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700654{
Dave Barach371e4e12016-07-08 09:38:52 -0400655 svm_region_t *rp;
656 int i;
657 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700658
Dave Barach371e4e12016-07-08 09:38:52 -0400659 if (!svm_get_root_rp ())
660 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700661
Dave Barach371e4e12016-07-08 09:38:52 -0400662 for (i = 0; i < vec_len (am->mapped_shmem_regions); i++)
663 {
664 rp = am->mapped_shmem_regions[i];
665 svm_region_unmap (rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700666 }
667
Dave Barach371e4e12016-07-08 09:38:52 -0400668 vec_free (am->mapped_shmem_regions);
669 am->shmem_hdr = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700670
Dave Barach371e4e12016-07-08 09:38:52 -0400671 svm_region_exit ();
672 /* $$$ more careful cleanup, valgrind run... */
673 vec_free (am->msg_handlers);
674 vec_free (am->msg_endian_handlers);
675 vec_free (am->msg_print_handlers);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700676}
677
Dave Barach371e4e12016-07-08 09:38:52 -0400678void
679vl_msg_api_send_shmem (unix_shared_memory_queue_t * q, u8 * elem)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700680{
Dave Barach371e4e12016-07-08 09:38:52 -0400681 api_main_t *am = &api_main;
682 uword *trace = (uword *) elem;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700683
Dave Barach371e4e12016-07-08 09:38:52 -0400684 if (am->tx_trace && am->tx_trace->enabled)
685 vl_msg_api_trace (am, am->tx_trace, (void *) trace[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700686
Dave Barach371e4e12016-07-08 09:38:52 -0400687 (void) unix_shared_memory_queue_add (q, elem, 0 /* nowait */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700688}
689
Dave Barach371e4e12016-07-08 09:38:52 -0400690void
691vl_msg_api_send_shmem_nolock (unix_shared_memory_queue_t * q, u8 * elem)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700692{
Dave Barach371e4e12016-07-08 09:38:52 -0400693 api_main_t *am = &api_main;
694 uword *trace = (uword *) elem;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700695
Dave Barach371e4e12016-07-08 09:38:52 -0400696 if (am->tx_trace && am->tx_trace->enabled)
697 vl_msg_api_trace (am, am->tx_trace, (void *) trace[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700698
Dave Barach371e4e12016-07-08 09:38:52 -0400699 (void) unix_shared_memory_queue_add_nolock (q, elem);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700700}
701
Dave Barach557d1282016-11-10 14:22:49 -0500702u32
703vl_api_get_msg_index (u8 * name_and_crc)
Dave Barach371e4e12016-07-08 09:38:52 -0400704{
Dave Barach557d1282016-11-10 14:22:49 -0500705 api_main_t *am = &api_main;
706 uword *p;
Dave Barach371e4e12016-07-08 09:38:52 -0400707
Dave Barach557d1282016-11-10 14:22:49 -0500708 if (am->msg_index_by_name_and_crc)
709 {
710 p = hash_get_mem (am->msg_index_by_name_and_crc, name_and_crc);
711 if (p)
712 return p[0];
713 }
714 return ~0;
Dave Barach371e4e12016-07-08 09:38:52 -0400715}
716
Dave Barach371e4e12016-07-08 09:38:52 -0400717static inline vl_api_registration_t *
718vl_api_client_index_to_registration_internal (u32 handle)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700719{
Dave Barach371e4e12016-07-08 09:38:52 -0400720 vl_api_registration_t **regpp;
721 vl_api_registration_t *regp;
722 api_main_t *am = &api_main;
723 u32 index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700724
Dave Barach371e4e12016-07-08 09:38:52 -0400725 index = vl_msg_api_handle_get_index (handle);
726 if ((am->shmem_hdr->application_restarts & VL_API_EPOCH_MASK)
727 != vl_msg_api_handle_get_epoch (handle))
728 {
729 vl_msg_api_increment_missing_client_counter ();
730 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700731 }
732
Dave Barach371e4e12016-07-08 09:38:52 -0400733 regpp = am->vl_clients + index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700734
Dave Barach371e4e12016-07-08 09:38:52 -0400735 if (pool_is_free (am->vl_clients, regpp))
736 {
737 vl_msg_api_increment_missing_client_counter ();
738 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700739 }
Dave Barach371e4e12016-07-08 09:38:52 -0400740 regp = *regpp;
741 return (regp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700742}
743
Dave Barach371e4e12016-07-08 09:38:52 -0400744vl_api_registration_t *
745vl_api_client_index_to_registration (u32 index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700746{
Dave Barach59b25652017-09-10 15:04:27 -0400747 if (PREDICT_FALSE (socket_main.current_rp != 0))
748 return socket_main.current_rp;
749
Dave Barach371e4e12016-07-08 09:38:52 -0400750 return (vl_api_client_index_to_registration_internal (index));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700751}
752
Dave Barach371e4e12016-07-08 09:38:52 -0400753unix_shared_memory_queue_t *
754vl_api_client_index_to_input_queue (u32 index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700755{
Dave Barach371e4e12016-07-08 09:38:52 -0400756 vl_api_registration_t *regp;
Dave Barachfc262a02016-12-14 14:49:55 -0500757 api_main_t *am = &api_main;
758
759 /* Special case: vlib trying to send itself a message */
760 if (index == (u32) ~ 0)
761 return (am->shmem_hdr->vl_input_queue);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700762
Dave Barach371e4e12016-07-08 09:38:52 -0400763 regp = vl_api_client_index_to_registration_internal (index);
764 if (!regp)
765 return 0;
766 return (regp->vl_input_queue);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700767}
768
Dave Barach371e4e12016-07-08 09:38:52 -0400769/*
770 * fd.io coding-style-patch-verification: ON
771 *
772 * Local Variables:
773 * eval: (c-set-style "gnu")
774 * End:
775 */