blob: f5892c17e734f83cb31f2883a813a2bd5603818e [file] [log] [blame]
Florin Coras7baeb712019-01-04 17:05:43 -08001/*
2 * Copyright (c) 2019 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this
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 */
15
16#include <vcl/vcl_locked.h>
17#include <vcl/vcl_private.h>
18
19typedef struct vcl_locked_session_
20{
Florin Corasf9240dc2019-01-15 08:03:17 -080021 clib_spinlock_t lock;
Florin Coras7baeb712019-01-04 17:05:43 -080022 u32 session_index;
23 u32 worker_index;
24 u32 vls_index;
Florin Corasf9240dc2019-01-15 08:03:17 -080025 u32 *workers_subscribed;
Florin Coras2d675d72019-01-28 15:54:27 -080026 clib_bitmap_t *listeners;
Florin Coras7baeb712019-01-04 17:05:43 -080027} vcl_locked_session_t;
28
Florin Coras2d675d72019-01-28 15:54:27 -080029typedef struct vls_local_
30{
31 int vls_wrk_index;
32 volatile int vls_mt_n_threads;
33 pthread_mutex_t vls_mt_mq_mlock;
34 pthread_mutex_t vls_mt_spool_mlock;
35 volatile u8 select_mp_check;
36 volatile u8 epoll_mp_check;
37} vls_process_local_t;
38
39static vls_process_local_t vls_local;
40static vls_process_local_t *vlsl = &vls_local;
41
42typedef struct vls_main_
Florin Coras7baeb712019-01-04 17:05:43 -080043{
44 vcl_locked_session_t *vls_pool;
45 clib_rwlock_t vls_table_lock;
46 uword *session_index_to_vlsh_table;
47} vls_main_t;
48
Florin Coras2d675d72019-01-28 15:54:27 -080049vls_main_t *vlsm;
Florin Coras7baeb712019-01-04 17:05:43 -080050
51static inline void
52vls_table_rlock (void)
53{
54 clib_rwlock_reader_lock (&vlsm->vls_table_lock);
55}
56
57static inline void
58vls_table_runlock (void)
59{
60 clib_rwlock_reader_unlock (&vlsm->vls_table_lock);
61}
62
63static inline void
64vls_table_wlock (void)
65{
66 clib_rwlock_writer_lock (&vlsm->vls_table_lock);
67}
68
69static inline void
70vls_table_wunlock (void)
71{
72 clib_rwlock_writer_unlock (&vlsm->vls_table_lock);
73}
74
Florin Coras0ef8ef22019-01-18 08:37:13 -080075typedef enum
76{
77 VLS_MT_OP_READ,
78 VLS_MT_OP_WRITE,
79 VLS_MT_OP_SPOOL,
80 VLS_MT_OP_XPOLL,
81} vls_mt_ops_t;
82
83typedef enum
84{
85 VLS_MT_LOCK_MQ = 1 << 0,
86 VLS_MT_LOCK_SPOOL = 1 << 1
87} vls_mt_lock_type_t;
88
Florin Coras0ef8ef22019-01-18 08:37:13 -080089static void
90vls_mt_add (void)
91{
Florin Coras2d675d72019-01-28 15:54:27 -080092 vlsl->vls_mt_n_threads += 1;
93 vcl_set_worker_index (vlsl->vls_wrk_index);
Florin Coras0ef8ef22019-01-18 08:37:13 -080094}
95
96static inline void
97vls_mt_mq_lock (void)
98{
Florin Coras2d675d72019-01-28 15:54:27 -080099 pthread_mutex_lock (&vlsl->vls_mt_mq_mlock);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800100}
101
102static inline void
103vls_mt_mq_unlock (void)
104{
Florin Coras2d675d72019-01-28 15:54:27 -0800105 pthread_mutex_unlock (&vlsl->vls_mt_mq_mlock);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800106}
107
108static inline void
109vls_mt_spool_lock (void)
110{
Florin Coras2d675d72019-01-28 15:54:27 -0800111 pthread_mutex_lock (&vlsl->vls_mt_spool_mlock);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800112}
113
114static inline void
115vls_mt_create_unlock (void)
116{
Florin Coras2d675d72019-01-28 15:54:27 -0800117 pthread_mutex_unlock (&vlsl->vls_mt_spool_mlock);
118}
119
120static void
121vls_mt_locks_init (void)
122{
123 pthread_mutex_init (&vlsl->vls_mt_mq_mlock, NULL);
124 pthread_mutex_init (&vlsl->vls_mt_spool_mlock, NULL);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800125}
126
Florin Coras7baeb712019-01-04 17:05:43 -0800127static inline vcl_session_handle_t
128vls_to_sh (vcl_locked_session_t * vls)
129{
Florin Corasf9240dc2019-01-15 08:03:17 -0800130 return vcl_session_handle_from_index (vls->session_index);
Florin Coras7baeb712019-01-04 17:05:43 -0800131}
132
133static inline vcl_session_handle_t
134vls_to_sh_tu (vcl_locked_session_t * vls)
135{
136 vcl_session_handle_t sh;
137 sh = vls_to_sh (vls);
138 vls_table_runlock ();
139 return sh;
140}
141
142static vls_handle_t
143vls_alloc (vcl_session_handle_t sh)
144{
145 vcl_locked_session_t *vls;
146
147 vls_table_wlock ();
148 pool_get (vlsm->vls_pool, vls);
149 vls->session_index = vppcom_session_index (sh);
150 vls->worker_index = vppcom_session_worker (sh);
151 vls->vls_index = vls - vlsm->vls_pool;
152 hash_set (vlsm->session_index_to_vlsh_table, vls->session_index,
153 vls->vls_index);
154 clib_spinlock_init (&vls->lock);
155 vls_table_wunlock ();
156 return vls->vls_index;
157}
158
159static vcl_locked_session_t *
160vls_get (vls_handle_t vlsh)
161{
162 if (pool_is_free_index (vlsm->vls_pool, vlsh))
163 return 0;
164 return pool_elt_at_index (vlsm->vls_pool, vlsh);
165}
166
167static void
Florin Coras0ef8ef22019-01-18 08:37:13 -0800168vls_free (vcl_locked_session_t * vls)
Florin Coras7baeb712019-01-04 17:05:43 -0800169{
Florin Coras0ef8ef22019-01-18 08:37:13 -0800170 ASSERT (vls != 0);
171 hash_unset (vlsm->session_index_to_vlsh_table, vls->session_index);
172 clib_spinlock_free (&vls->lock);
173 pool_put (vlsm->vls_pool, vls);
Florin Coras7baeb712019-01-04 17:05:43 -0800174}
175
176static vcl_locked_session_t *
177vls_get_and_lock (vls_handle_t vlsh)
178{
179 vcl_locked_session_t *vls;
180 if (pool_is_free_index (vlsm->vls_pool, vlsh))
181 return 0;
182 vls = pool_elt_at_index (vlsm->vls_pool, vlsh);
183 clib_spinlock_lock (&vls->lock);
184 return vls;
185}
186
187static vcl_locked_session_t *
188vls_get_w_dlock (vls_handle_t vlsh)
189{
190 vcl_locked_session_t *vls;
191 vls_table_rlock ();
192 vls = vls_get_and_lock (vlsh);
193 if (!vls)
194 vls_table_runlock ();
195 return vls;
196}
197
198static inline void
Florin Coras2d675d72019-01-28 15:54:27 -0800199vls_lock (vcl_locked_session_t * vls)
200{
201 clib_spinlock_lock (&vls->lock);
202}
203
204static inline void
Florin Coras7baeb712019-01-04 17:05:43 -0800205vls_unlock (vcl_locked_session_t * vls)
206{
207 clib_spinlock_unlock (&vls->lock);
208}
209
210static inline void
211vls_get_and_unlock (vls_handle_t vlsh)
212{
213 vcl_locked_session_t *vls;
214 vls_table_rlock ();
215 vls = vls_get (vlsh);
216 vls_unlock (vls);
217 vls_table_runlock ();
218}
219
220static inline void
221vls_dunlock (vcl_locked_session_t * vls)
222{
223 vls_unlock (vls);
224 vls_table_runlock ();
225}
226
Florin Coras2d675d72019-01-28 15:54:27 -0800227vcl_session_handle_t
228vlsh_to_sh (vls_handle_t vlsh)
229{
230 vcl_locked_session_t *vls;
231 int rv;
232
233 vls = vls_get_w_dlock (vlsh);
234 if (!vls)
235 return INVALID_SESSION_ID;
236 rv = vls_to_sh (vls);
237 vls_dunlock (vls);
238 return rv;
239}
240
241vcl_session_handle_t
242vlsh_to_session_index (vls_handle_t vlsh)
243{
244 vcl_session_handle_t sh;
245 sh = vlsh_to_sh (vlsh);
246 return vppcom_session_index (sh);
247}
248
249vls_handle_t
250vls_si_to_vlsh (u32 session_index)
251{
252 uword *vlshp;
253 vlshp = hash_get (vlsm->session_index_to_vlsh_table, session_index);
254 return vlshp ? *vlshp : VLS_INVALID_HANDLE;
255}
256
257vls_handle_t
258vls_session_index_to_vlsh (uint32_t session_index)
259{
260 vls_handle_t vlsh;
261
262 vls_table_rlock ();
263 vlsh = vls_si_to_vlsh (session_index);
264 vls_table_runlock ();
265
266 return vlsh;
267}
268
Florin Corasf9240dc2019-01-15 08:03:17 -0800269u8
270vls_is_shared (vcl_locked_session_t * vls)
271{
272 return vec_len (vls->workers_subscribed);
273}
274
Florin Coras0ef8ef22019-01-18 08:37:13 -0800275u8
276vls_is_shared_by_wrk (vcl_locked_session_t * vls, u32 wrk_index)
Florin Corasf9240dc2019-01-15 08:03:17 -0800277{
Florin Coras0ef8ef22019-01-18 08:37:13 -0800278 int i;
279 for (i = 0; i < vec_len (vls->workers_subscribed); i++)
280 if (vls->workers_subscribed[i] == wrk_index)
281 return 1;
282 return 0;
283}
284
Florin Coras2d675d72019-01-28 15:54:27 -0800285static void
286vls_listener_wrk_set (vcl_locked_session_t * vls, u32 wrk_index, u8 is_active)
287{
288 clib_bitmap_set (vls->listeners, wrk_index, is_active);
289}
290
291static u8
292vls_listener_wrk_is_active (vcl_locked_session_t * vls, u32 wrk_index)
293{
294 return (clib_bitmap_get (vls->listeners, wrk_index) == 1);
295}
296
297static void
298vls_listener_wrk_start_listen (vcl_locked_session_t * vls, u32 wrk_index)
299{
300 vppcom_session_listen (vls_to_sh (vls), ~0);
301 vls_listener_wrk_set (vls, wrk_index, 1 /* is_active */ );
302}
303
304static void
305vls_listener_wrk_stop_listen (vcl_locked_session_t * vls, u32 wrk_index)
306{
307 vcl_worker_t *wrk;
308 vcl_session_t *s;
309
310 wrk = vcl_worker_get (wrk_index);
311 s = vcl_session_get (wrk, vls->session_index);
312 if (s->session_state != STATE_LISTEN)
313 return;
314 vppcom_send_unbind_sock (wrk, s->vpp_handle);
315 s->session_state = STATE_LISTEN_NO_MQ;
316 vls_listener_wrk_set (vls, wrk_index, 0 /* is_active */ );
317}
318
Florin Coras0ef8ef22019-01-18 08:37:13 -0800319int
320vls_unshare_session (vcl_locked_session_t * vls, vcl_worker_t * wrk)
321{
Florin Coras2d675d72019-01-28 15:54:27 -0800322 int i, do_disconnect;
Florin Corasf9240dc2019-01-15 08:03:17 -0800323 vcl_session_t *s;
Florin Coras2d675d72019-01-28 15:54:27 -0800324
325 s = vcl_session_get (wrk, vls->session_index);
326 if (s->session_state == STATE_LISTEN)
327 vls_listener_wrk_set (vls, wrk->wrk_index, 0 /* is_active */ );
Florin Corasf9240dc2019-01-15 08:03:17 -0800328
329 for (i = 0; i < vec_len (vls->workers_subscribed); i++)
330 {
331 if (vls->workers_subscribed[i] != wrk->wrk_index)
332 continue;
333
Florin Corasf9240dc2019-01-15 08:03:17 -0800334 if (s->rx_fifo)
335 {
336 svm_fifo_del_subscriber (s->rx_fifo, wrk->vpp_wrk_index);
337 svm_fifo_del_subscriber (s->tx_fifo, wrk->vpp_wrk_index);
338 }
339 vec_del1 (vls->workers_subscribed, i);
Florin Coras2d675d72019-01-28 15:54:27 -0800340 do_disconnect = s->session_state == STATE_LISTEN;
341 vcl_session_cleanup (wrk, s, vcl_session_handle (s), do_disconnect);
Florin Corasf9240dc2019-01-15 08:03:17 -0800342 return 0;
343 }
344
Florin Coras0ef8ef22019-01-18 08:37:13 -0800345 /* Return, if this is not the owning worker */
346 if (vls->worker_index != wrk->wrk_index)
347 return 0;
348
Florin Coras0ef8ef22019-01-18 08:37:13 -0800349 /* Check if we can change owner or close */
350 if (vec_len (vls->workers_subscribed))
Florin Corasf9240dc2019-01-15 08:03:17 -0800351 {
Florin Corasf9240dc2019-01-15 08:03:17 -0800352 vls->worker_index = vls->workers_subscribed[0];
353 vec_del1 (vls->workers_subscribed, 0);
354 vcl_send_session_worker_update (wrk, s, vls->worker_index);
355 if (vec_len (vls->workers_subscribed))
356 clib_warning ("more workers need to be updated");
357 }
Florin Coras0ef8ef22019-01-18 08:37:13 -0800358 else
359 {
360 vcl_session_cleanup (wrk, s, vcl_session_handle (s),
361 1 /* do_disconnect */ );
362 }
Florin Corasf9240dc2019-01-15 08:03:17 -0800363
364 return 0;
365}
366
367void
368vls_share_vcl_session (vcl_worker_t * wrk, vcl_session_t * s)
369{
370 vcl_locked_session_t *vls;
371
Florin Coras2d675d72019-01-28 15:54:27 -0800372 vls = vls_get (vls_si_to_vlsh (s->session_index));
Florin Corasf9240dc2019-01-15 08:03:17 -0800373 if (!vls)
374 return;
Florin Coras2d675d72019-01-28 15:54:27 -0800375 vls_lock (vls);
Florin Corasf9240dc2019-01-15 08:03:17 -0800376 vec_add1 (vls->workers_subscribed, wrk->wrk_index);
377 if (s->rx_fifo)
378 {
379 svm_fifo_add_subscriber (s->rx_fifo, wrk->vpp_wrk_index);
380 svm_fifo_add_subscriber (s->tx_fifo, wrk->vpp_wrk_index);
381 }
Florin Coras2d675d72019-01-28 15:54:27 -0800382 else if (s->session_state == STATE_LISTEN)
383 {
384 s->session_state = STATE_LISTEN_NO_MQ;
385 }
386
387 vls_unlock (vls);
Florin Corasf9240dc2019-01-15 08:03:17 -0800388}
389
390void
391vls_worker_copy_on_fork (vcl_worker_t * parent_wrk)
392{
393 vcl_worker_t *wrk = vcl_worker_get_current ();
394 vcl_session_t *s;
395
396 wrk->vpp_event_queues = vec_dup (parent_wrk->vpp_event_queues);
397 wrk->sessions = pool_dup (parent_wrk->sessions);
398 wrk->session_index_by_vpp_handles =
399 hash_dup (parent_wrk->session_index_by_vpp_handles);
Florin Coras2d675d72019-01-28 15:54:27 -0800400 vls_table_wlock ();
Florin Corasf9240dc2019-01-15 08:03:17 -0800401
402 /* *INDENT-OFF* */
403 pool_foreach (s, wrk->sessions, ({
404 vls_share_vcl_session (wrk, s);
405 }));
406 /* *INDENT-ON* */
Florin Coras2d675d72019-01-28 15:54:27 -0800407
408 vls_table_wunlock ();
Florin Corasf9240dc2019-01-15 08:03:17 -0800409}
410
Florin Coras0ef8ef22019-01-18 08:37:13 -0800411static void
412vls_mt_acq_locks (vcl_locked_session_t * vls, vls_mt_ops_t op, int *locks_acq)
413{
414 vcl_worker_t *wrk = vcl_worker_get_current ();
415 vcl_session_t *s = 0;
416 int is_nonblk = 0;
417
418 if (vls)
419 {
420 s = vcl_session_get (wrk, vls->session_index);
421 if (PREDICT_FALSE (!s))
422 return;
423 is_nonblk = VCL_SESS_ATTR_TEST (s->attr, VCL_SESS_ATTR_NONBLOCK);
424 }
425
426 switch (op)
427 {
428 case VLS_MT_OP_READ:
429 if (!is_nonblk)
430 is_nonblk = vcl_session_read_ready (s) != 0;
431 if (!is_nonblk)
432 {
433 vls_mt_mq_lock ();
434 *locks_acq |= VLS_MT_LOCK_MQ;
435 }
436 break;
437 case VLS_MT_OP_WRITE:
438 if (!is_nonblk)
439 is_nonblk = vcl_session_write_ready (s) != 0;
440 if (!is_nonblk)
441 {
442 vls_mt_mq_lock ();
443 *locks_acq |= VLS_MT_LOCK_MQ;
444 }
445 break;
446 case VLS_MT_OP_XPOLL:
447 vls_mt_mq_lock ();
448 *locks_acq |= VLS_MT_LOCK_MQ;
449 break;
450 case VLS_MT_OP_SPOOL:
451 vls_mt_spool_lock ();
452 *locks_acq |= VLS_MT_LOCK_SPOOL;
453 break;
454 default:
455 break;
456 }
457}
458
459static void
460vls_mt_rel_locks (int locks_acq)
461{
462 if (locks_acq & VLS_MT_LOCK_MQ)
463 vls_mt_mq_unlock ();
464 if (locks_acq & VLS_MT_LOCK_SPOOL)
465 vls_mt_create_unlock ();
466}
467
468#define vls_mt_guard(_vls, _op) \
469 int _locks_acq = 0; \
470 if (PREDICT_FALSE (vcl_get_worker_index () == ~0)); \
471 vls_mt_add (); \
Florin Coras2d675d72019-01-28 15:54:27 -0800472 if (PREDICT_FALSE (vlsl->vls_mt_n_threads > 1)) \
Florin Coras0ef8ef22019-01-18 08:37:13 -0800473 vls_mt_acq_locks (_vls, _op, &_locks_acq); \
474
475#define vls_mt_unguard() \
476 if (PREDICT_FALSE (_locks_acq)) \
477 vls_mt_rel_locks (_locks_acq)
478
Florin Coras7baeb712019-01-04 17:05:43 -0800479int
480vls_write (vls_handle_t vlsh, void *buf, size_t nbytes)
481{
482 vcl_locked_session_t *vls;
483 int rv;
484
485 if (!(vls = vls_get_w_dlock (vlsh)))
486 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800487
488 vls_mt_guard (vls, VLS_MT_OP_WRITE);
Florin Coras7baeb712019-01-04 17:05:43 -0800489 rv = vppcom_session_write (vls_to_sh_tu (vls), buf, nbytes);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800490 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800491 vls_get_and_unlock (vlsh);
492 return rv;
493}
494
495int
496vls_write_msg (vls_handle_t vlsh, void *buf, size_t nbytes)
497{
498 vcl_locked_session_t *vls;
499 int rv;
500
501 if (!(vls = vls_get_w_dlock (vlsh)))
502 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800503 vls_mt_guard (vls, VLS_MT_OP_WRITE);
Florin Coras7baeb712019-01-04 17:05:43 -0800504 rv = vppcom_session_write_msg (vls_to_sh_tu (vls), buf, nbytes);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800505 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800506 vls_get_and_unlock (vlsh);
507 return rv;
508}
509
510int
511vls_sendto (vls_handle_t vlsh, void *buf, int buflen, int flags,
512 vppcom_endpt_t * ep)
513{
514 vcl_locked_session_t *vls;
515 int rv;
516
517 if (!(vls = vls_get_w_dlock (vlsh)))
518 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800519 vls_mt_guard (vls, VLS_MT_OP_WRITE);
Florin Coras7baeb712019-01-04 17:05:43 -0800520 rv = vppcom_session_sendto (vls_to_sh_tu (vls), buf, buflen, flags, ep);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800521 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800522 vls_get_and_unlock (vlsh);
523 return rv;
524}
525
526ssize_t
527vls_read (vls_handle_t vlsh, void *buf, size_t nbytes)
528{
529 vcl_locked_session_t *vls;
530 int rv;
531
532 if (!(vls = vls_get_w_dlock (vlsh)))
533 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800534 vls_mt_guard (vls, VLS_MT_OP_READ);
Florin Coras7baeb712019-01-04 17:05:43 -0800535 rv = vppcom_session_read (vls_to_sh_tu (vls), buf, nbytes);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800536 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800537 vls_get_and_unlock (vlsh);
538 return rv;
539}
540
541ssize_t
542vls_recvfrom (vls_handle_t vlsh, void *buffer, uint32_t buflen, int flags,
543 vppcom_endpt_t * ep)
544{
545 vcl_locked_session_t *vls;
546 int rv;
547
548 if (!(vls = vls_get_w_dlock (vlsh)))
549 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800550 vls_mt_guard (vls, VLS_MT_OP_READ);
Florin Coras7baeb712019-01-04 17:05:43 -0800551 rv = vppcom_session_recvfrom (vls_to_sh_tu (vls), buffer, buflen, flags,
552 ep);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800553 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800554 vls_get_and_unlock (vlsh);
555 return rv;
556}
557
558int
559vls_attr (vls_handle_t vlsh, uint32_t op, void *buffer, uint32_t * buflen)
560{
561 vcl_locked_session_t *vls;
562 int rv;
563
564 if (!(vls = vls_get_w_dlock (vlsh)))
565 return VPPCOM_EBADFD;
566 rv = vppcom_session_attr (vls_to_sh_tu (vls), op, buffer, buflen);
567 vls_get_and_unlock (vlsh);
568 return rv;
569}
570
571int
572vls_bind (vls_handle_t vlsh, vppcom_endpt_t * ep)
573{
574 vcl_locked_session_t *vls;
575 int rv;
576
577 if (!(vls = vls_get_w_dlock (vlsh)))
578 return VPPCOM_EBADFD;
579 rv = vppcom_session_bind (vls_to_sh_tu (vls), ep);
580 vls_get_and_unlock (vlsh);
581 return rv;
582}
583
584int
585vls_listen (vls_handle_t vlsh, int q_len)
586{
587 vcl_locked_session_t *vls;
588 int rv;
589
590 if (!(vls = vls_get_w_dlock (vlsh)))
591 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800592 vls_mt_guard (vls, VLS_MT_OP_XPOLL);
Florin Coras7baeb712019-01-04 17:05:43 -0800593 rv = vppcom_session_listen (vls_to_sh_tu (vls), q_len);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800594 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800595 vls_get_and_unlock (vlsh);
596 return rv;
597}
598
599int
600vls_connect (vls_handle_t vlsh, vppcom_endpt_t * server_ep)
601{
602 vcl_locked_session_t *vls;
603 int rv;
604
605 if (!(vls = vls_get_w_dlock (vlsh)))
606 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800607 vls_mt_guard (vls, VLS_MT_OP_XPOLL);
Florin Coras7baeb712019-01-04 17:05:43 -0800608 rv = vppcom_session_connect (vls_to_sh_tu (vls), server_ep);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800609 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800610 vls_get_and_unlock (vlsh);
611 return rv;
612}
613
Florin Coras2d675d72019-01-28 15:54:27 -0800614static inline void
615vls_mp_checks (vcl_locked_session_t * vls, int is_add)
616{
617 vcl_worker_t *wrk = vcl_worker_get_current ();
618 vcl_session_t *s;
619
620 s = vcl_session_get (wrk, vls->session_index);
621 switch (s->session_state)
622 {
623 case STATE_LISTEN:
624 if (is_add)
625 {
626 if (vls->worker_index == wrk->wrk_index)
627 vls_listener_wrk_set (vls, wrk->wrk_index, 1 /* is_active */ );
628 break;
629 }
630 vls_listener_wrk_stop_listen (vls, vls->worker_index);
631 break;
632 case STATE_LISTEN_NO_MQ:
633 if (!is_add)
634 break;
635
636 /* Register worker as listener */
637 vls_listener_wrk_start_listen (vls, wrk->wrk_index);
638
639 /* If owner worker did not attempt to accept/xpoll on the session,
640 * force a listen stop for it, since it may not be interested in
641 * accepting new sessions.
642 * This is pretty much a hack done to give app workers the illusion
643 * that it is fine to listen and not accept new sessions for a
644 * given listener. Without it, we would accumulate unhandled
645 * accepts on the passive worker message queue. */
646 if (!vls_listener_wrk_is_active (vls, vls->worker_index))
647 vls_listener_wrk_stop_listen (vls, vls->worker_index);
648 break;
649 default:
650 break;
651 }
652}
653
Florin Coras7baeb712019-01-04 17:05:43 -0800654vls_handle_t
655vls_accept (vls_handle_t listener_vlsh, vppcom_endpt_t * ep, int flags)
656{
657 vls_handle_t accepted_vlsh;
658 vcl_locked_session_t *vls;
659 int sh;
660
661 if (!(vls = vls_get_w_dlock (listener_vlsh)))
662 return VPPCOM_EBADFD;
Florin Coras2d675d72019-01-28 15:54:27 -0800663 if (vcl_n_workers () > 1)
664 vls_mp_checks (vls, 1 /* is_add */ );
Florin Coras0ef8ef22019-01-18 08:37:13 -0800665 vls_mt_guard (vls, VLS_MT_OP_SPOOL);
Florin Coras7baeb712019-01-04 17:05:43 -0800666 sh = vppcom_session_accept (vls_to_sh_tu (vls), ep, flags);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800667 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800668 vls_get_and_unlock (listener_vlsh);
669 if (sh < 0)
670 return sh;
671 accepted_vlsh = vls_alloc (sh);
672 if (PREDICT_FALSE (accepted_vlsh == VLS_INVALID_HANDLE))
673 vppcom_session_close (sh);
674 return accepted_vlsh;
675}
676
677vls_handle_t
678vls_create (uint8_t proto, uint8_t is_nonblocking)
679{
680 vcl_session_handle_t sh;
681 vls_handle_t vlsh;
682
Florin Coras0ef8ef22019-01-18 08:37:13 -0800683 vls_mt_guard (0, VLS_MT_OP_SPOOL);
Florin Coras7baeb712019-01-04 17:05:43 -0800684 sh = vppcom_session_create (proto, is_nonblocking);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800685 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800686 if (sh == INVALID_SESSION_ID)
687 return VLS_INVALID_HANDLE;
688
689 vlsh = vls_alloc (sh);
690 if (PREDICT_FALSE (vlsh == VLS_INVALID_HANDLE))
691 vppcom_session_close (sh);
692
693 return vlsh;
694}
695
696int
697vls_close (vls_handle_t vlsh)
698{
699 vcl_locked_session_t *vls;
Florin Corasf9240dc2019-01-15 08:03:17 -0800700 int rv;
Florin Coras7baeb712019-01-04 17:05:43 -0800701
Florin Coras0ef8ef22019-01-18 08:37:13 -0800702 vls_table_wlock ();
Florin Coras7baeb712019-01-04 17:05:43 -0800703
Florin Coras0ef8ef22019-01-18 08:37:13 -0800704 vls = vls_get_and_lock (vlsh);
705 if (!vls)
706 {
707 vls_table_wunlock ();
708 return VPPCOM_EBADFD;
709 }
710
711 vls_mt_guard (0, VLS_MT_OP_SPOOL);
Florin Corasf9240dc2019-01-15 08:03:17 -0800712 if (vls_is_shared (vls))
713 {
Florin Coras0ef8ef22019-01-18 08:37:13 -0800714 /* At least two workers share the session so vls won't be freed */
715 vls_unshare_session (vls, vcl_worker_get_current ());
716 vls_unlock (vls);
717 vls_mt_unguard ();
718 vls_table_wunlock ();
Florin Corasf9240dc2019-01-15 08:03:17 -0800719 return VPPCOM_OK;
720 }
721
Florin Coras0ef8ef22019-01-18 08:37:13 -0800722 rv = vppcom_session_close (vls_to_sh (vls));
723 vls_free (vls);
724 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800725
Florin Coras0ef8ef22019-01-18 08:37:13 -0800726 vls_table_wunlock ();
727
Florin Coras7baeb712019-01-04 17:05:43 -0800728 return rv;
729}
730
731vls_handle_t
732vls_epoll_create (void)
733{
734 vcl_session_handle_t sh;
735 vls_handle_t vlsh;
736
737 sh = vppcom_epoll_create ();
738 if (sh == INVALID_SESSION_ID)
739 return VLS_INVALID_HANDLE;
740
741 vlsh = vls_alloc (sh);
742 if (vlsh == VLS_INVALID_HANDLE)
743 vppcom_session_close (sh);
744
745 return vlsh;
746}
747
Florin Coras2d675d72019-01-28 15:54:27 -0800748static void
749vls_epoll_ctl_mp_checks (vcl_locked_session_t * vls, int op)
750{
751 if (vcl_n_workers () <= 1)
752 {
753 vlsl->epoll_mp_check = 1;
754 return;
755 }
756
757 if (op == EPOLL_CTL_MOD)
758 return;
759
760 vlsl->epoll_mp_check = 1;
761 vls_mp_checks (vls, op == EPOLL_CTL_ADD);
762}
763
Florin Coras7baeb712019-01-04 17:05:43 -0800764int
765vls_epoll_ctl (vls_handle_t ep_vlsh, int op, vls_handle_t vlsh,
766 struct epoll_event *event)
767{
768 vcl_locked_session_t *ep_vls, *vls;
769 vcl_session_handle_t ep_sh, sh;
770 int rv;
771
772 vls_table_rlock ();
773 ep_vls = vls_get_and_lock (ep_vlsh);
774 vls = vls_get_and_lock (vlsh);
775 ep_sh = vls_to_sh (ep_vls);
776 sh = vls_to_sh (vls);
Florin Coras2d675d72019-01-28 15:54:27 -0800777
778 if (PREDICT_FALSE (!vlsl->epoll_mp_check))
779 vls_epoll_ctl_mp_checks (vls, op);
780
Florin Coras7baeb712019-01-04 17:05:43 -0800781 vls_table_runlock ();
782
783 rv = vppcom_epoll_ctl (ep_sh, op, sh, event);
784
785 vls_table_rlock ();
786 ep_vls = vls_get (ep_vlsh);
787 vls = vls_get (vlsh);
788 vls_unlock (vls);
789 vls_unlock (ep_vls);
790 vls_table_runlock ();
791 return rv;
792}
793
794int
795vls_epoll_wait (vls_handle_t ep_vlsh, struct epoll_event *events,
796 int maxevents, double wait_for_time)
797{
798 vcl_locked_session_t *vls;
799 int rv;
800
801 if (!(vls = vls_get_w_dlock (ep_vlsh)))
802 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800803 vls_mt_guard (0, VLS_MT_OP_XPOLL);
Florin Coras7baeb712019-01-04 17:05:43 -0800804 rv = vppcom_epoll_wait (vls_to_sh_tu (vls), events, maxevents,
805 wait_for_time);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800806 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800807 vls_get_and_unlock (ep_vlsh);
808 return rv;
809}
810
Florin Coras2d675d72019-01-28 15:54:27 -0800811static void
812vls_select_mp_checks (vcl_si_set * read_map)
813{
814 vcl_locked_session_t *vls;
815 vcl_worker_t *wrk;
816 vcl_session_t *s;
817 u32 si;
818
819 if (vcl_n_workers () <= 1)
820 {
821 vlsl->select_mp_check = 1;
822 return;
823 }
824
825 if (!read_map)
826 return;
827
828 vlsl->select_mp_check = 1;
829 wrk = vcl_worker_get_current ();
830
831 /* *INDENT-OFF* */
832 clib_bitmap_foreach (si, read_map, ({
833 s = vcl_session_get (wrk, si);
834 if (s->session_state == STATE_LISTEN)
835 {
836 vls = vls_get (vls_session_index_to_vlsh (si));
837 vls_mp_checks (vls, 1 /* is_add */);
838 }
839 }));
840 /* *INDENT-ON* */
841}
842
Florin Coras0ef8ef22019-01-18 08:37:13 -0800843int
844vls_select (int n_bits, vcl_si_set * read_map, vcl_si_set * write_map,
845 vcl_si_set * except_map, double wait_for_time)
846{
847 int rv;
Florin Coras2d675d72019-01-28 15:54:27 -0800848
Florin Coras0ef8ef22019-01-18 08:37:13 -0800849 vls_mt_guard (0, VLS_MT_OP_XPOLL);
Florin Coras2d675d72019-01-28 15:54:27 -0800850 if (PREDICT_FALSE (!vlsl->select_mp_check))
851 vls_select_mp_checks (read_map);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800852 rv = vppcom_select (n_bits, read_map, write_map, except_map, wait_for_time);
853 vls_mt_unguard ();
854 return rv;
855}
856
Florin Corasf9240dc2019-01-15 08:03:17 -0800857static void
Florin Coras0ef8ef22019-01-18 08:37:13 -0800858vls_unshare_vcl_worker_sessions (vcl_worker_t * wrk)
859{
860 u32 current_wrk, is_current;
861 vcl_locked_session_t *vls;
862 vcl_session_t *s;
863
864 current_wrk = vcl_get_worker_index ();
865 is_current = current_wrk == wrk->wrk_index;
866 vls_table_wlock ();
867
868 /* *INDENT-OFF* */
869 pool_foreach (s, wrk->sessions, ({
870 vls = vls_get (vls_si_to_vlsh (s->session_index));
871 if (vls && (is_current || vls_is_shared_by_wrk (vls, current_wrk)))
872 vls_unshare_session (vls, wrk);
873 }));
874 /* *INDENT-ON* */
875
876 vls_table_wunlock ();
877}
878
879static void
880vls_cleanup_vcl_worker (vcl_worker_t * wrk)
881{
882 /* Unshare sessions and also cleanup worker since child may have
883 * called _exit () and therefore vcl may not catch the event */
884 vls_unshare_vcl_worker_sessions (wrk);
885 vcl_worker_cleanup (wrk, 1 /* notify vpp */ );
886}
887
888static void
Florin Corasf9240dc2019-01-15 08:03:17 -0800889vls_cleanup_forked_child (vcl_worker_t * wrk, vcl_worker_t * child_wrk)
890{
891 vcl_worker_t *sub_child;
892 int tries = 0;
893
894 if (child_wrk->forked_child != ~0)
895 {
896 sub_child = vcl_worker_get_if_valid (child_wrk->forked_child);
897 if (sub_child)
898 {
899 /* Wait a bit, maybe the process is going away */
900 while (kill (sub_child->current_pid, 0) >= 0 && tries++ < 50)
901 usleep (1e3);
902 if (kill (sub_child->current_pid, 0) < 0)
903 vls_cleanup_forked_child (child_wrk, sub_child);
904 }
905 }
Florin Coras0ef8ef22019-01-18 08:37:13 -0800906 vls_cleanup_vcl_worker (child_wrk);
907 VDBG (0, "Cleaned up forked child wrk %u", child_wrk->wrk_index);
Florin Corasf9240dc2019-01-15 08:03:17 -0800908 wrk->forked_child = ~0;
909}
910
911static struct sigaction old_sa;
912
913static void
914vls_intercept_sigchld_handler (int signum, siginfo_t * si, void *uc)
915{
916 vcl_worker_t *wrk, *child_wrk;
917
918 if (vcl_get_worker_index () == ~0)
919 return;
920
921 if (sigaction (SIGCHLD, &old_sa, 0))
922 {
923 VERR ("couldn't restore sigchld");
924 exit (-1);
925 }
926
927 wrk = vcl_worker_get_current ();
928 if (wrk->forked_child == ~0)
929 return;
930
931 child_wrk = vcl_worker_get_if_valid (wrk->forked_child);
932 if (!child_wrk)
933 goto done;
934
935 if (si && si->si_pid != child_wrk->current_pid)
936 {
937 VDBG (0, "unexpected child pid %u", si->si_pid);
938 goto done;
939 }
940 vls_cleanup_forked_child (wrk, child_wrk);
941
942done:
943 if (old_sa.sa_flags & SA_SIGINFO)
944 {
945 void (*fn) (int, siginfo_t *, void *) = old_sa.sa_sigaction;
946 fn (signum, si, uc);
947 }
948 else
949 {
950 void (*fn) (int) = old_sa.sa_handler;
951 if (fn)
952 fn (signum);
953 }
954}
955
956static void
957vls_incercept_sigchld ()
958{
959 struct sigaction sa;
960 clib_memset (&sa, 0, sizeof (sa));
961 sa.sa_sigaction = vls_intercept_sigchld_handler;
962 sa.sa_flags = SA_SIGINFO;
963 if (sigaction (SIGCHLD, &sa, &old_sa))
964 {
965 VERR ("couldn't intercept sigchld");
966 exit (-1);
967 }
968}
969
970static void
971vls_app_pre_fork (void)
972{
973 vls_incercept_sigchld ();
974 vcl_flush_mq_events ();
975}
976
977static void
978vls_app_fork_child_handler (void)
979{
980 vcl_worker_t *parent_wrk;
981 int rv, parent_wrk_index;
982 u8 *child_name;
983
984 parent_wrk_index = vcl_get_worker_index ();
985 VDBG (0, "initializing forked child %u with parent wrk %u", getpid (),
986 parent_wrk_index);
987
988 /*
989 * Allocate worker
990 */
991 vcl_set_worker_index (~0);
992 if (!vcl_worker_alloc_and_init ())
993 VERR ("couldn't allocate new worker");
994
995 /*
996 * Attach to binary api
997 */
998 child_name = format (0, "%v-child-%u%c", vcm->app_name, getpid (), 0);
999 vcl_cleanup_bapi ();
1000 vppcom_api_hookup ();
1001 vcm->app_state = STATE_APP_START;
1002 rv = vppcom_connect_to_vpp ((char *) child_name);
1003 vec_free (child_name);
1004 if (rv)
1005 {
1006 VERR ("couldn't connect to VPP!");
1007 return;
1008 }
1009
1010 /*
1011 * Register worker with vpp and share sessions
1012 */
1013 vcl_worker_register_with_vpp ();
1014 parent_wrk = vcl_worker_get (parent_wrk_index);
1015 vls_worker_copy_on_fork (parent_wrk);
1016 parent_wrk->forked_child = vcl_get_worker_index ();
1017
Florin Coras0ef8ef22019-01-18 08:37:13 -08001018 /* Reset number of threads and set wrk index */
Florin Coras2d675d72019-01-28 15:54:27 -08001019 vlsl->vls_mt_n_threads = 0;
1020 vlsl->vls_wrk_index = vcl_get_worker_index ();
1021 vlsl->select_mp_check = 0;
1022 vlsl->epoll_mp_check = 0;
1023 vls_mt_locks_init ();
Florin Coras0ef8ef22019-01-18 08:37:13 -08001024
Florin Corasf9240dc2019-01-15 08:03:17 -08001025 VDBG (0, "forked child main worker initialized");
1026 vcm->forking = 0;
1027}
1028
1029static void
1030vls_app_fork_parent_handler (void)
1031{
1032 vcm->forking = 1;
1033 while (vcm->forking)
1034 ;
1035}
1036
Florin Coras0ef8ef22019-01-18 08:37:13 -08001037void
1038vls_app_exit (void)
1039{
1040 /* Unshare the sessions. VCL will clean up the worker */
1041 vls_unshare_vcl_worker_sessions (vcl_worker_get_current ());
1042}
1043
Florin Coras7baeb712019-01-04 17:05:43 -08001044int
1045vls_app_create (char *app_name)
1046{
1047 int rv;
Florin Coras0ef8ef22019-01-18 08:37:13 -08001048
Florin Coras7baeb712019-01-04 17:05:43 -08001049 if ((rv = vppcom_app_create (app_name)))
1050 return rv;
Florin Coras2d675d72019-01-28 15:54:27 -08001051 vlsm = clib_mem_alloc (sizeof (vls_main_t));
1052 clib_memset (vlsm, 0, sizeof (*vlsm));
Florin Coras7baeb712019-01-04 17:05:43 -08001053 clib_rwlock_init (&vlsm->vls_table_lock);
Florin Corasf9240dc2019-01-15 08:03:17 -08001054 pthread_atfork (vls_app_pre_fork, vls_app_fork_parent_handler,
1055 vls_app_fork_child_handler);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001056 atexit (vls_app_exit);
Florin Coras2d675d72019-01-28 15:54:27 -08001057 vlsl->vls_wrk_index = vcl_get_worker_index ();
1058 vls_mt_locks_init ();
Florin Coras7baeb712019-01-04 17:05:43 -08001059 return VPPCOM_OK;
1060}
1061
1062/*
1063 * fd.io coding-style-patch-verification: ON
1064 *
1065 * Local Variables:
1066 * eval: (c-set-style "gnu")
1067 * End:
1068 */