blob: fb19b5df03f6af97d46a240dad1599ec8819d4f1 [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:
Florin Coras78b5fa62019-02-21 20:04:15 -0800438 ASSERT (s);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800439 if (!is_nonblk)
440 is_nonblk = vcl_session_write_ready (s) != 0;
441 if (!is_nonblk)
442 {
443 vls_mt_mq_lock ();
444 *locks_acq |= VLS_MT_LOCK_MQ;
445 }
446 break;
447 case VLS_MT_OP_XPOLL:
448 vls_mt_mq_lock ();
449 *locks_acq |= VLS_MT_LOCK_MQ;
450 break;
451 case VLS_MT_OP_SPOOL:
452 vls_mt_spool_lock ();
453 *locks_acq |= VLS_MT_LOCK_SPOOL;
454 break;
455 default:
456 break;
457 }
458}
459
460static void
461vls_mt_rel_locks (int locks_acq)
462{
463 if (locks_acq & VLS_MT_LOCK_MQ)
464 vls_mt_mq_unlock ();
465 if (locks_acq & VLS_MT_LOCK_SPOOL)
466 vls_mt_create_unlock ();
467}
468
469#define vls_mt_guard(_vls, _op) \
470 int _locks_acq = 0; \
471 if (PREDICT_FALSE (vcl_get_worker_index () == ~0)); \
472 vls_mt_add (); \
Florin Coras2d675d72019-01-28 15:54:27 -0800473 if (PREDICT_FALSE (vlsl->vls_mt_n_threads > 1)) \
Florin Coras0ef8ef22019-01-18 08:37:13 -0800474 vls_mt_acq_locks (_vls, _op, &_locks_acq); \
475
476#define vls_mt_unguard() \
477 if (PREDICT_FALSE (_locks_acq)) \
478 vls_mt_rel_locks (_locks_acq)
479
Florin Coras7baeb712019-01-04 17:05:43 -0800480int
481vls_write (vls_handle_t vlsh, void *buf, size_t nbytes)
482{
483 vcl_locked_session_t *vls;
484 int rv;
485
486 if (!(vls = vls_get_w_dlock (vlsh)))
487 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800488
489 vls_mt_guard (vls, VLS_MT_OP_WRITE);
Florin Coras7baeb712019-01-04 17:05:43 -0800490 rv = vppcom_session_write (vls_to_sh_tu (vls), buf, nbytes);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800491 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800492 vls_get_and_unlock (vlsh);
493 return rv;
494}
495
496int
497vls_write_msg (vls_handle_t vlsh, void *buf, size_t nbytes)
498{
499 vcl_locked_session_t *vls;
500 int rv;
501
502 if (!(vls = vls_get_w_dlock (vlsh)))
503 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800504 vls_mt_guard (vls, VLS_MT_OP_WRITE);
Florin Coras7baeb712019-01-04 17:05:43 -0800505 rv = vppcom_session_write_msg (vls_to_sh_tu (vls), buf, nbytes);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800506 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800507 vls_get_and_unlock (vlsh);
508 return rv;
509}
510
511int
512vls_sendto (vls_handle_t vlsh, void *buf, int buflen, int flags,
513 vppcom_endpt_t * ep)
514{
515 vcl_locked_session_t *vls;
516 int rv;
517
518 if (!(vls = vls_get_w_dlock (vlsh)))
519 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800520 vls_mt_guard (vls, VLS_MT_OP_WRITE);
Florin Coras7baeb712019-01-04 17:05:43 -0800521 rv = vppcom_session_sendto (vls_to_sh_tu (vls), buf, buflen, flags, ep);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800522 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800523 vls_get_and_unlock (vlsh);
524 return rv;
525}
526
527ssize_t
528vls_read (vls_handle_t vlsh, void *buf, size_t nbytes)
529{
530 vcl_locked_session_t *vls;
531 int rv;
532
533 if (!(vls = vls_get_w_dlock (vlsh)))
534 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800535 vls_mt_guard (vls, VLS_MT_OP_READ);
Florin Coras7baeb712019-01-04 17:05:43 -0800536 rv = vppcom_session_read (vls_to_sh_tu (vls), buf, nbytes);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800537 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800538 vls_get_and_unlock (vlsh);
539 return rv;
540}
541
542ssize_t
543vls_recvfrom (vls_handle_t vlsh, void *buffer, uint32_t buflen, int flags,
544 vppcom_endpt_t * ep)
545{
546 vcl_locked_session_t *vls;
547 int rv;
548
549 if (!(vls = vls_get_w_dlock (vlsh)))
550 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800551 vls_mt_guard (vls, VLS_MT_OP_READ);
Florin Coras7baeb712019-01-04 17:05:43 -0800552 rv = vppcom_session_recvfrom (vls_to_sh_tu (vls), buffer, buflen, flags,
553 ep);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800554 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800555 vls_get_and_unlock (vlsh);
556 return rv;
557}
558
559int
560vls_attr (vls_handle_t vlsh, uint32_t op, void *buffer, uint32_t * buflen)
561{
562 vcl_locked_session_t *vls;
563 int rv;
564
565 if (!(vls = vls_get_w_dlock (vlsh)))
566 return VPPCOM_EBADFD;
567 rv = vppcom_session_attr (vls_to_sh_tu (vls), op, buffer, buflen);
568 vls_get_and_unlock (vlsh);
569 return rv;
570}
571
572int
573vls_bind (vls_handle_t vlsh, vppcom_endpt_t * ep)
574{
575 vcl_locked_session_t *vls;
576 int rv;
577
578 if (!(vls = vls_get_w_dlock (vlsh)))
579 return VPPCOM_EBADFD;
580 rv = vppcom_session_bind (vls_to_sh_tu (vls), ep);
581 vls_get_and_unlock (vlsh);
582 return rv;
583}
584
585int
586vls_listen (vls_handle_t vlsh, int q_len)
587{
588 vcl_locked_session_t *vls;
589 int rv;
590
591 if (!(vls = vls_get_w_dlock (vlsh)))
592 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800593 vls_mt_guard (vls, VLS_MT_OP_XPOLL);
Florin Coras7baeb712019-01-04 17:05:43 -0800594 rv = vppcom_session_listen (vls_to_sh_tu (vls), q_len);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800595 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800596 vls_get_and_unlock (vlsh);
597 return rv;
598}
599
600int
601vls_connect (vls_handle_t vlsh, vppcom_endpt_t * server_ep)
602{
603 vcl_locked_session_t *vls;
604 int rv;
605
606 if (!(vls = vls_get_w_dlock (vlsh)))
607 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800608 vls_mt_guard (vls, VLS_MT_OP_XPOLL);
Florin Coras7baeb712019-01-04 17:05:43 -0800609 rv = vppcom_session_connect (vls_to_sh_tu (vls), server_ep);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800610 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800611 vls_get_and_unlock (vlsh);
612 return rv;
613}
614
Florin Coras2d675d72019-01-28 15:54:27 -0800615static inline void
616vls_mp_checks (vcl_locked_session_t * vls, int is_add)
617{
618 vcl_worker_t *wrk = vcl_worker_get_current ();
619 vcl_session_t *s;
620
621 s = vcl_session_get (wrk, vls->session_index);
622 switch (s->session_state)
623 {
624 case STATE_LISTEN:
625 if (is_add)
626 {
627 if (vls->worker_index == wrk->wrk_index)
628 vls_listener_wrk_set (vls, wrk->wrk_index, 1 /* is_active */ );
629 break;
630 }
631 vls_listener_wrk_stop_listen (vls, vls->worker_index);
632 break;
633 case STATE_LISTEN_NO_MQ:
634 if (!is_add)
635 break;
636
637 /* Register worker as listener */
638 vls_listener_wrk_start_listen (vls, wrk->wrk_index);
639
640 /* If owner worker did not attempt to accept/xpoll on the session,
641 * force a listen stop for it, since it may not be interested in
642 * accepting new sessions.
643 * This is pretty much a hack done to give app workers the illusion
644 * that it is fine to listen and not accept new sessions for a
645 * given listener. Without it, we would accumulate unhandled
646 * accepts on the passive worker message queue. */
647 if (!vls_listener_wrk_is_active (vls, vls->worker_index))
648 vls_listener_wrk_stop_listen (vls, vls->worker_index);
649 break;
650 default:
651 break;
652 }
653}
654
Florin Coras7baeb712019-01-04 17:05:43 -0800655vls_handle_t
656vls_accept (vls_handle_t listener_vlsh, vppcom_endpt_t * ep, int flags)
657{
658 vls_handle_t accepted_vlsh;
659 vcl_locked_session_t *vls;
660 int sh;
661
662 if (!(vls = vls_get_w_dlock (listener_vlsh)))
663 return VPPCOM_EBADFD;
Florin Coras2d675d72019-01-28 15:54:27 -0800664 if (vcl_n_workers () > 1)
665 vls_mp_checks (vls, 1 /* is_add */ );
Florin Coras0ef8ef22019-01-18 08:37:13 -0800666 vls_mt_guard (vls, VLS_MT_OP_SPOOL);
Florin Coras7baeb712019-01-04 17:05:43 -0800667 sh = vppcom_session_accept (vls_to_sh_tu (vls), ep, flags);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800668 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800669 vls_get_and_unlock (listener_vlsh);
670 if (sh < 0)
671 return sh;
672 accepted_vlsh = vls_alloc (sh);
673 if (PREDICT_FALSE (accepted_vlsh == VLS_INVALID_HANDLE))
674 vppcom_session_close (sh);
675 return accepted_vlsh;
676}
677
678vls_handle_t
679vls_create (uint8_t proto, uint8_t is_nonblocking)
680{
681 vcl_session_handle_t sh;
682 vls_handle_t vlsh;
683
Florin Coras0ef8ef22019-01-18 08:37:13 -0800684 vls_mt_guard (0, VLS_MT_OP_SPOOL);
Florin Coras7baeb712019-01-04 17:05:43 -0800685 sh = vppcom_session_create (proto, is_nonblocking);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800686 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800687 if (sh == INVALID_SESSION_ID)
688 return VLS_INVALID_HANDLE;
689
690 vlsh = vls_alloc (sh);
691 if (PREDICT_FALSE (vlsh == VLS_INVALID_HANDLE))
692 vppcom_session_close (sh);
693
694 return vlsh;
695}
696
697int
698vls_close (vls_handle_t vlsh)
699{
700 vcl_locked_session_t *vls;
Florin Corasf9240dc2019-01-15 08:03:17 -0800701 int rv;
Florin Coras7baeb712019-01-04 17:05:43 -0800702
Florin Coras0ef8ef22019-01-18 08:37:13 -0800703 vls_table_wlock ();
Florin Coras7baeb712019-01-04 17:05:43 -0800704
Florin Coras0ef8ef22019-01-18 08:37:13 -0800705 vls = vls_get_and_lock (vlsh);
706 if (!vls)
707 {
708 vls_table_wunlock ();
709 return VPPCOM_EBADFD;
710 }
711
712 vls_mt_guard (0, VLS_MT_OP_SPOOL);
Florin Corasf9240dc2019-01-15 08:03:17 -0800713 if (vls_is_shared (vls))
714 {
Florin Coras0ef8ef22019-01-18 08:37:13 -0800715 /* At least two workers share the session so vls won't be freed */
716 vls_unshare_session (vls, vcl_worker_get_current ());
717 vls_unlock (vls);
718 vls_mt_unguard ();
719 vls_table_wunlock ();
Florin Corasf9240dc2019-01-15 08:03:17 -0800720 return VPPCOM_OK;
721 }
722
Florin Coras0ef8ef22019-01-18 08:37:13 -0800723 rv = vppcom_session_close (vls_to_sh (vls));
724 vls_free (vls);
725 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800726
Florin Coras0ef8ef22019-01-18 08:37:13 -0800727 vls_table_wunlock ();
728
Florin Coras7baeb712019-01-04 17:05:43 -0800729 return rv;
730}
731
732vls_handle_t
733vls_epoll_create (void)
734{
735 vcl_session_handle_t sh;
736 vls_handle_t vlsh;
737
738 sh = vppcom_epoll_create ();
739 if (sh == INVALID_SESSION_ID)
740 return VLS_INVALID_HANDLE;
741
742 vlsh = vls_alloc (sh);
743 if (vlsh == VLS_INVALID_HANDLE)
744 vppcom_session_close (sh);
745
746 return vlsh;
747}
748
Florin Coras2d675d72019-01-28 15:54:27 -0800749static void
750vls_epoll_ctl_mp_checks (vcl_locked_session_t * vls, int op)
751{
752 if (vcl_n_workers () <= 1)
753 {
754 vlsl->epoll_mp_check = 1;
755 return;
756 }
757
758 if (op == EPOLL_CTL_MOD)
759 return;
760
761 vlsl->epoll_mp_check = 1;
762 vls_mp_checks (vls, op == EPOLL_CTL_ADD);
763}
764
Florin Coras7baeb712019-01-04 17:05:43 -0800765int
766vls_epoll_ctl (vls_handle_t ep_vlsh, int op, vls_handle_t vlsh,
767 struct epoll_event *event)
768{
769 vcl_locked_session_t *ep_vls, *vls;
770 vcl_session_handle_t ep_sh, sh;
771 int rv;
772
773 vls_table_rlock ();
774 ep_vls = vls_get_and_lock (ep_vlsh);
775 vls = vls_get_and_lock (vlsh);
776 ep_sh = vls_to_sh (ep_vls);
777 sh = vls_to_sh (vls);
Florin Coras2d675d72019-01-28 15:54:27 -0800778
779 if (PREDICT_FALSE (!vlsl->epoll_mp_check))
780 vls_epoll_ctl_mp_checks (vls, op);
781
Florin Coras7baeb712019-01-04 17:05:43 -0800782 vls_table_runlock ();
783
784 rv = vppcom_epoll_ctl (ep_sh, op, sh, event);
785
786 vls_table_rlock ();
787 ep_vls = vls_get (ep_vlsh);
788 vls = vls_get (vlsh);
789 vls_unlock (vls);
790 vls_unlock (ep_vls);
791 vls_table_runlock ();
792 return rv;
793}
794
795int
796vls_epoll_wait (vls_handle_t ep_vlsh, struct epoll_event *events,
797 int maxevents, double wait_for_time)
798{
799 vcl_locked_session_t *vls;
800 int rv;
801
802 if (!(vls = vls_get_w_dlock (ep_vlsh)))
803 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800804 vls_mt_guard (0, VLS_MT_OP_XPOLL);
Florin Coras7baeb712019-01-04 17:05:43 -0800805 rv = vppcom_epoll_wait (vls_to_sh_tu (vls), events, maxevents,
806 wait_for_time);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800807 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -0800808 vls_get_and_unlock (ep_vlsh);
809 return rv;
810}
811
Florin Coras2d675d72019-01-28 15:54:27 -0800812static void
813vls_select_mp_checks (vcl_si_set * read_map)
814{
815 vcl_locked_session_t *vls;
816 vcl_worker_t *wrk;
817 vcl_session_t *s;
818 u32 si;
819
820 if (vcl_n_workers () <= 1)
821 {
822 vlsl->select_mp_check = 1;
823 return;
824 }
825
826 if (!read_map)
827 return;
828
829 vlsl->select_mp_check = 1;
830 wrk = vcl_worker_get_current ();
831
832 /* *INDENT-OFF* */
833 clib_bitmap_foreach (si, read_map, ({
834 s = vcl_session_get (wrk, si);
835 if (s->session_state == STATE_LISTEN)
836 {
837 vls = vls_get (vls_session_index_to_vlsh (si));
838 vls_mp_checks (vls, 1 /* is_add */);
839 }
840 }));
841 /* *INDENT-ON* */
842}
843
Florin Coras0ef8ef22019-01-18 08:37:13 -0800844int
845vls_select (int n_bits, vcl_si_set * read_map, vcl_si_set * write_map,
846 vcl_si_set * except_map, double wait_for_time)
847{
848 int rv;
Florin Coras2d675d72019-01-28 15:54:27 -0800849
Florin Coras0ef8ef22019-01-18 08:37:13 -0800850 vls_mt_guard (0, VLS_MT_OP_XPOLL);
Florin Coras2d675d72019-01-28 15:54:27 -0800851 if (PREDICT_FALSE (!vlsl->select_mp_check))
852 vls_select_mp_checks (read_map);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800853 rv = vppcom_select (n_bits, read_map, write_map, except_map, wait_for_time);
854 vls_mt_unguard ();
855 return rv;
856}
857
Florin Corasf9240dc2019-01-15 08:03:17 -0800858static void
Florin Coras0ef8ef22019-01-18 08:37:13 -0800859vls_unshare_vcl_worker_sessions (vcl_worker_t * wrk)
860{
861 u32 current_wrk, is_current;
862 vcl_locked_session_t *vls;
863 vcl_session_t *s;
864
Florin Coras14ed6df2019-03-06 21:13:42 -0800865 if (pool_elts (vcm->workers) <= 1)
866 return;
867
Florin Coras0ef8ef22019-01-18 08:37:13 -0800868 current_wrk = vcl_get_worker_index ();
869 is_current = current_wrk == wrk->wrk_index;
870 vls_table_wlock ();
871
872 /* *INDENT-OFF* */
873 pool_foreach (s, wrk->sessions, ({
874 vls = vls_get (vls_si_to_vlsh (s->session_index));
875 if (vls && (is_current || vls_is_shared_by_wrk (vls, current_wrk)))
876 vls_unshare_session (vls, wrk);
877 }));
878 /* *INDENT-ON* */
879
880 vls_table_wunlock ();
881}
882
883static void
884vls_cleanup_vcl_worker (vcl_worker_t * wrk)
885{
886 /* Unshare sessions and also cleanup worker since child may have
887 * called _exit () and therefore vcl may not catch the event */
888 vls_unshare_vcl_worker_sessions (wrk);
889 vcl_worker_cleanup (wrk, 1 /* notify vpp */ );
890}
891
892static void
Florin Corasf9240dc2019-01-15 08:03:17 -0800893vls_cleanup_forked_child (vcl_worker_t * wrk, vcl_worker_t * child_wrk)
894{
895 vcl_worker_t *sub_child;
896 int tries = 0;
897
898 if (child_wrk->forked_child != ~0)
899 {
900 sub_child = vcl_worker_get_if_valid (child_wrk->forked_child);
901 if (sub_child)
902 {
903 /* Wait a bit, maybe the process is going away */
904 while (kill (sub_child->current_pid, 0) >= 0 && tries++ < 50)
905 usleep (1e3);
906 if (kill (sub_child->current_pid, 0) < 0)
907 vls_cleanup_forked_child (child_wrk, sub_child);
908 }
909 }
Florin Coras0ef8ef22019-01-18 08:37:13 -0800910 vls_cleanup_vcl_worker (child_wrk);
911 VDBG (0, "Cleaned up forked child wrk %u", child_wrk->wrk_index);
Florin Corasf9240dc2019-01-15 08:03:17 -0800912 wrk->forked_child = ~0;
913}
914
915static struct sigaction old_sa;
916
917static void
918vls_intercept_sigchld_handler (int signum, siginfo_t * si, void *uc)
919{
920 vcl_worker_t *wrk, *child_wrk;
921
922 if (vcl_get_worker_index () == ~0)
923 return;
924
925 if (sigaction (SIGCHLD, &old_sa, 0))
926 {
927 VERR ("couldn't restore sigchld");
928 exit (-1);
929 }
930
931 wrk = vcl_worker_get_current ();
932 if (wrk->forked_child == ~0)
933 return;
934
935 child_wrk = vcl_worker_get_if_valid (wrk->forked_child);
936 if (!child_wrk)
937 goto done;
938
939 if (si && si->si_pid != child_wrk->current_pid)
940 {
941 VDBG (0, "unexpected child pid %u", si->si_pid);
942 goto done;
943 }
944 vls_cleanup_forked_child (wrk, child_wrk);
945
946done:
947 if (old_sa.sa_flags & SA_SIGINFO)
948 {
949 void (*fn) (int, siginfo_t *, void *) = old_sa.sa_sigaction;
950 fn (signum, si, uc);
951 }
952 else
953 {
954 void (*fn) (int) = old_sa.sa_handler;
955 if (fn)
956 fn (signum);
957 }
958}
959
960static void
961vls_incercept_sigchld ()
962{
963 struct sigaction sa;
964 clib_memset (&sa, 0, sizeof (sa));
965 sa.sa_sigaction = vls_intercept_sigchld_handler;
966 sa.sa_flags = SA_SIGINFO;
967 if (sigaction (SIGCHLD, &sa, &old_sa))
968 {
969 VERR ("couldn't intercept sigchld");
970 exit (-1);
971 }
972}
973
974static void
975vls_app_pre_fork (void)
976{
977 vls_incercept_sigchld ();
978 vcl_flush_mq_events ();
979}
980
981static void
982vls_app_fork_child_handler (void)
983{
984 vcl_worker_t *parent_wrk;
985 int rv, parent_wrk_index;
986 u8 *child_name;
987
988 parent_wrk_index = vcl_get_worker_index ();
989 VDBG (0, "initializing forked child %u with parent wrk %u", getpid (),
990 parent_wrk_index);
991
992 /*
993 * Allocate worker
994 */
995 vcl_set_worker_index (~0);
996 if (!vcl_worker_alloc_and_init ())
997 VERR ("couldn't allocate new worker");
998
999 /*
1000 * Attach to binary api
1001 */
1002 child_name = format (0, "%v-child-%u%c", vcm->app_name, getpid (), 0);
1003 vcl_cleanup_bapi ();
1004 vppcom_api_hookup ();
1005 vcm->app_state = STATE_APP_START;
1006 rv = vppcom_connect_to_vpp ((char *) child_name);
1007 vec_free (child_name);
1008 if (rv)
1009 {
1010 VERR ("couldn't connect to VPP!");
1011 return;
1012 }
1013
1014 /*
1015 * Register worker with vpp and share sessions
1016 */
1017 vcl_worker_register_with_vpp ();
1018 parent_wrk = vcl_worker_get (parent_wrk_index);
1019 vls_worker_copy_on_fork (parent_wrk);
1020 parent_wrk->forked_child = vcl_get_worker_index ();
1021
Florin Coras0ef8ef22019-01-18 08:37:13 -08001022 /* Reset number of threads and set wrk index */
Florin Coras2d675d72019-01-28 15:54:27 -08001023 vlsl->vls_mt_n_threads = 0;
1024 vlsl->vls_wrk_index = vcl_get_worker_index ();
1025 vlsl->select_mp_check = 0;
1026 vlsl->epoll_mp_check = 0;
1027 vls_mt_locks_init ();
Florin Coras0ef8ef22019-01-18 08:37:13 -08001028
Florin Corasf9240dc2019-01-15 08:03:17 -08001029 VDBG (0, "forked child main worker initialized");
1030 vcm->forking = 0;
1031}
1032
1033static void
1034vls_app_fork_parent_handler (void)
1035{
1036 vcm->forking = 1;
1037 while (vcm->forking)
1038 ;
1039}
1040
Florin Coras0ef8ef22019-01-18 08:37:13 -08001041void
1042vls_app_exit (void)
1043{
1044 /* Unshare the sessions. VCL will clean up the worker */
1045 vls_unshare_vcl_worker_sessions (vcl_worker_get_current ());
1046}
1047
Florin Coras7baeb712019-01-04 17:05:43 -08001048int
1049vls_app_create (char *app_name)
1050{
1051 int rv;
Florin Coras0ef8ef22019-01-18 08:37:13 -08001052
Florin Coras7baeb712019-01-04 17:05:43 -08001053 if ((rv = vppcom_app_create (app_name)))
1054 return rv;
Florin Coras2d675d72019-01-28 15:54:27 -08001055 vlsm = clib_mem_alloc (sizeof (vls_main_t));
1056 clib_memset (vlsm, 0, sizeof (*vlsm));
Florin Coras7baeb712019-01-04 17:05:43 -08001057 clib_rwlock_init (&vlsm->vls_table_lock);
Florin Corasf9240dc2019-01-15 08:03:17 -08001058 pthread_atfork (vls_app_pre_fork, vls_app_fork_parent_handler,
1059 vls_app_fork_child_handler);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001060 atexit (vls_app_exit);
Florin Coras2d675d72019-01-28 15:54:27 -08001061 vlsl->vls_wrk_index = vcl_get_worker_index ();
1062 vls_mt_locks_init ();
Florin Coras7baeb712019-01-04 17:05:43 -08001063 return VPPCOM_OK;
1064}
1065
1066/*
1067 * fd.io coding-style-patch-verification: ON
1068 *
1069 * Local Variables:
1070 * eval: (c-set-style "gnu")
1071 * End:
1072 */