blob: 9f3d6b56c2e8f924efae2ba4a56fea51bbb7225b [file] [log] [blame]
Florin Coras7baeb712019-01-04 17:05:43 -08001/*
Florin Coras5e618432021-07-26 18:19:25 -07002 * Copyright (c) 2021 Cisco and/or its affiliates.
Florin Coras7baeb712019-01-04 17:05:43 -08003 * 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
Florin Coras5e618432021-07-26 18:19:25 -070016/**
17 * VCL Locked Sessions (VLS) is a wrapper that synchronizes access to VCL APIs
18 * which are, by construction, not thread safe. To this end, VLS uses
19 * configuration and heuristics to detect how applications use sessions in
20 * an attempt to optimize the locking strategy. The modes of operation
21 * currently supported are the following:
22 *
23 * 1) per-process workers
24 *
25 * +----------+ +----------+
26 * | | | |
27 * | process0 | | process1 |
28 * | | | |
29 * +-----+----+ +-----+----+
30 * | |
31 * | |
32 * +-----+----+ +-----+----+
33 * | | | |
34 * | vls_wrk0 | | vls_wrk1 |
35 * | | | |
36 * +-----+----+ +-----+----+
37 * | |
38 * | |
39 * +-----+----+ +-----+----+
40 * | | | |
41 * | vcl_wrk0 | | vcl_wrk1 |
42 * | | | |
43 * +----------+ +----------+
44 *
45 * 2) per-thread workers 3) single-worker multi-thread
46 *
47 * +---------+ +---------+ +---------+ +---------+
48 * | | | | | | | |
49 * | thread0 | | thread1 | | thread0 | | thread1 |
50 * | | | | | | | |
51 * +--------++ +-+-------+ +--------++ +-+-------+
52 * | | | |
53 * | | | |
54 * +-+------+-+ +-+------+-+
55 * | | | |
56 * | vls_wrk0 | | vls_wrk0 |
57 * | | | |
58 * +-+------+-+ +----+-----+
59 * | | |
60 * | | |
61 * +--------+-+ +-+--------+ +----+-----+
62 * | | | | | |
63 * | vcl_wrk0 | | vcl_wrk1 | | vcl_wrk0 |
64 * | | | | | |
65 * +----------+ +----------+ +----------+
66 *
67 * 1) per-process workers: intercept fork calls and assume all children
68 * processes are new workers that must be registered with vcl. VLS
69 * sessions are cloned and shared between workers. Only shared sessions
70 * are locked on use and thereby only one process can interact with
71 * them at a time (explicit sharing).
72 *
73 * 2) per-thread workers: each newly detected pthread is assumed to be a new
74 * worker and is registered with vcl. Enabled via configuration.
75 * When a thread tries to access a session it does not own, a clone and
76 * share rpc request is sent to the owning thread via vcl and vpp.
77 * Consequently, a vls session can map to multiple vcl sessions, one per
78 * vcl worker. VLS sessions are locked on use (implicit sharing).
79 *
80 * 3) single-worker multi-thread: vls does not make any assumptions about
81 * application threads and therefore implements an aggressive locking
82 * strategy that limits access to underlying vcl resources based on type
83 * of interaction and locks vls session on use (implicit sharing).
84 */
85
Florin Coras7baeb712019-01-04 17:05:43 -080086#include <vcl/vcl_locked.h>
87#include <vcl/vcl_private.h>
88
Florin Coras243edd52020-03-04 22:20:12 +000089typedef struct vls_shared_data_
90{
Florin Coras5e618432021-07-26 18:19:25 -070091 clib_spinlock_t lock; /**< shared data lock */
92 u32 owner_wrk_index; /**< vcl wrk that owns session */
93 u32 *workers_subscribed; /**< vec of wrks subscribed to session */
94 clib_bitmap_t *listeners; /**< bitmap of wrks actively listening */
Florin Coras243edd52020-03-04 22:20:12 +000095} vls_shared_data_t;
96
Florin Coras7baeb712019-01-04 17:05:43 -080097typedef struct vcl_locked_session_
98{
Florin Coras5e618432021-07-26 18:19:25 -070099 clib_spinlock_t lock; /**< vls lock when in use */
100 u32 session_index; /**< vcl session index */
101 u32 vcl_wrk_index; /**< vcl worker index */
102 u32 vls_index; /**< index in vls pool */
103 u32 shared_data_index; /**< shared data index if any */
104 u32 owner_vcl_wrk_index; /**< vcl wrk of the vls wrk at alloc */
105 uword *vcl_wrk_index_to_session_index; /**< map vcl wrk to session */
Florin Coras978d48b2024-11-26 00:29:24 -0800106 int libc_epfd; /**< epoll fd for libc epoll */
Florin Coras7baeb712019-01-04 17:05:43 -0800107} vcl_locked_session_t;
108
Florin Coras243edd52020-03-04 22:20:12 +0000109typedef struct vls_worker_
110{
Florin Coras5e618432021-07-26 18:19:25 -0700111 clib_rwlock_t sh_to_vlsh_table_lock; /**< ht rwlock with mt workers */
112 vcl_locked_session_t *vls_pool; /**< pool of vls session */
113 uword *sh_to_vlsh_table; /**< map from vcl sh to vls sh */
114 u32 *pending_vcl_wrk_cleanup; /**< child vcl wrks to cleanup */
115 u32 vcl_wrk_index; /**< if 1:1 map vls to vcl wrk */
Florin Coras243edd52020-03-04 22:20:12 +0000116} vls_worker_t;
117
Florin Coras2d675d72019-01-28 15:54:27 -0800118typedef struct vls_local_
119{
Florin Coras5e618432021-07-26 18:19:25 -0700120 int vls_wrk_index; /**< vls wrk index, 1 per process */
121 volatile int vls_mt_n_threads; /**< number of threads detected */
Florin Coras2e2f9df2021-07-27 22:48:05 -0700122 clib_rwlock_t vls_pool_lock; /**< per process/wrk vls pool locks */
Florin Coras5e618432021-07-26 18:19:25 -0700123 pthread_mutex_t vls_mt_mq_mlock; /**< vcl mq lock */
124 pthread_mutex_t vls_mt_spool_mlock; /**< vcl select or pool lock */
125 volatile u8 select_mp_check; /**< flag set if select checks done */
Florin Coras2d675d72019-01-28 15:54:27 -0800126} vls_process_local_t;
127
128static vls_process_local_t vls_local;
129static vls_process_local_t *vlsl = &vls_local;
130
131typedef struct vls_main_
Florin Coras7baeb712019-01-04 17:05:43 -0800132{
Florin Coras5e618432021-07-26 18:19:25 -0700133 vls_worker_t *workers; /**< pool of vls workers */
Florin Coras5e618432021-07-26 18:19:25 -0700134 vls_shared_data_t *shared_data_pool; /**< inter proc pool of shared data */
135 clib_rwlock_t shared_data_lock; /**< shared data pool lock */
136 clib_spinlock_t worker_rpc_lock; /**< lock for inter-worker rpcs */
Florin Coras7baeb712019-01-04 17:05:43 -0800137} vls_main_t;
138
Florin Coras2d675d72019-01-28 15:54:27 -0800139vls_main_t *vlsm;
Florin Coras7baeb712019-01-04 17:05:43 -0800140
wanghanlindcacdc42020-12-28 16:19:05 +0800141typedef enum
142{
143 VLS_RPC_STATE_INIT,
144 VLS_RPC_STATE_SUCCESS,
145 VLS_RPC_STATE_SESSION_NOT_EXIST,
146} vls_rpc_state_e;
147
Florin Coras40c07ce2020-07-16 20:46:17 -0700148typedef enum vls_rpc_msg_type_
149{
150 VLS_RPC_CLONE_AND_SHARE,
hanlina3a48962020-07-13 11:09:15 +0800151 VLS_RPC_SESS_CLEANUP,
Florin Coras40c07ce2020-07-16 20:46:17 -0700152} vls_rpc_msg_type_e;
153
154typedef struct vls_rpc_msg_
155{
156 u8 type;
157 u8 data[0];
158} vls_rpc_msg_t;
159
160typedef struct vls_clone_and_share_msg_
161{
162 u32 vls_index; /**< vls to be shared */
hanlina3a48962020-07-13 11:09:15 +0800163 u32 session_index; /**< vcl session to be shared */
164 u32 origin_vls_wrk; /**< vls worker that initiated the rpc */
Florin Coras40c07ce2020-07-16 20:46:17 -0700165 u32 origin_vls_index; /**< vls session of the originator */
hanlina3a48962020-07-13 11:09:15 +0800166 u32 origin_vcl_wrk; /**< vcl worker that initiated the rpc */
167 u32 origin_session_index; /**< vcl session of the originator */
Florin Coras40c07ce2020-07-16 20:46:17 -0700168} vls_clone_and_share_msg_t;
169
hanlina3a48962020-07-13 11:09:15 +0800170typedef struct vls_sess_cleanup_msg_
171{
172 u32 session_index; /**< vcl session to be cleaned */
173 u32 origin_vcl_wrk; /**< worker that initiated the rpc */
174} vls_sess_cleanup_msg_t;
175
176void vls_send_session_cleanup_rpc (vcl_worker_t * wrk,
177 u32 dst_wrk_index, u32 dst_session_index);
wanghanlindcacdc42020-12-28 16:19:05 +0800178void vls_send_clone_and_share_rpc (vcl_worker_t *wrk, u32 origin_vls_index,
hanlina3a48962020-07-13 11:09:15 +0800179 u32 session_index, u32 vls_wrk_index,
180 u32 dst_wrk_index, u32 dst_vls_index,
181 u32 dst_session_index);
wanghanlind72a0342021-05-12 17:00:29 +0800182static void vls_cleanup_forked_child (vcl_worker_t *wrk,
183 vcl_worker_t *child_wrk);
184static void vls_handle_pending_wrk_cleanup (void);
hanlina3a48962020-07-13 11:09:15 +0800185
Florin Coras243edd52020-03-04 22:20:12 +0000186static inline u32
187vls_get_worker_index (void)
188{
liuyacan603e1a42021-07-22 15:52:01 +0800189 return vlsl->vls_wrk_index;
Florin Coras243edd52020-03-04 22:20:12 +0000190}
191
192static u32
193vls_shared_data_alloc (void)
194{
195 vls_shared_data_t *vls_shd;
196 u32 shd_index;
197
198 clib_rwlock_writer_lock (&vlsm->shared_data_lock);
199 pool_get_zero (vlsm->shared_data_pool, vls_shd);
200 clib_spinlock_init (&vls_shd->lock);
201 shd_index = vls_shd - vlsm->shared_data_pool;
202 clib_rwlock_writer_unlock (&vlsm->shared_data_lock);
203
204 return shd_index;
205}
206
207static u32
208vls_shared_data_index (vls_shared_data_t * vls_shd)
209{
210 return vls_shd - vlsm->shared_data_pool;
211}
212
213vls_shared_data_t *
214vls_shared_data_get (u32 shd_index)
215{
216 if (pool_is_free_index (vlsm->shared_data_pool, shd_index))
217 return 0;
218 return pool_elt_at_index (vlsm->shared_data_pool, shd_index);
219}
220
221static void
222vls_shared_data_free (u32 shd_index)
223{
224 vls_shared_data_t *vls_shd;
225
226 clib_rwlock_writer_lock (&vlsm->shared_data_lock);
227 vls_shd = vls_shared_data_get (shd_index);
228 clib_spinlock_free (&vls_shd->lock);
229 clib_bitmap_free (vls_shd->listeners);
230 vec_free (vls_shd->workers_subscribed);
231 pool_put (vlsm->shared_data_pool, vls_shd);
232 clib_rwlock_writer_unlock (&vlsm->shared_data_lock);
233}
234
235static inline void
236vls_shared_data_pool_rlock (void)
237{
238 clib_rwlock_reader_lock (&vlsm->shared_data_lock);
239}
240
241static inline void
242vls_shared_data_pool_runlock (void)
243{
244 clib_rwlock_reader_unlock (&vlsm->shared_data_lock);
245}
246
Florin Coras7baeb712019-01-04 17:05:43 -0800247static inline void
Florin Coras5e618432021-07-26 18:19:25 -0700248vls_mt_pool_rlock (void)
Florin Coras7baeb712019-01-04 17:05:43 -0800249{
Florin Coras243edd52020-03-04 22:20:12 +0000250 if (vlsl->vls_mt_n_threads > 1)
Florin Coras2e2f9df2021-07-27 22:48:05 -0700251 clib_rwlock_reader_lock (&vlsl->vls_pool_lock);
Florin Coras7baeb712019-01-04 17:05:43 -0800252}
253
254static inline void
Florin Coras5e618432021-07-26 18:19:25 -0700255vls_mt_pool_runlock (void)
Florin Coras7baeb712019-01-04 17:05:43 -0800256{
Florin Coras243edd52020-03-04 22:20:12 +0000257 if (vlsl->vls_mt_n_threads > 1)
Florin Coras2e2f9df2021-07-27 22:48:05 -0700258 clib_rwlock_reader_unlock (&vlsl->vls_pool_lock);
Florin Coras7baeb712019-01-04 17:05:43 -0800259}
260
261static inline void
Florin Coras5e618432021-07-26 18:19:25 -0700262vls_mt_pool_wlock (void)
Florin Coras7baeb712019-01-04 17:05:43 -0800263{
Florin Coras243edd52020-03-04 22:20:12 +0000264 if (vlsl->vls_mt_n_threads > 1)
Florin Coras2e2f9df2021-07-27 22:48:05 -0700265 clib_rwlock_writer_lock (&vlsl->vls_pool_lock);
Florin Coras7baeb712019-01-04 17:05:43 -0800266}
267
268static inline void
Florin Coras5e618432021-07-26 18:19:25 -0700269vls_mt_pool_wunlock (void)
Florin Coras7baeb712019-01-04 17:05:43 -0800270{
Florin Coras243edd52020-03-04 22:20:12 +0000271 if (vlsl->vls_mt_n_threads > 1)
Florin Coras2e2f9df2021-07-27 22:48:05 -0700272 clib_rwlock_writer_unlock (&vlsl->vls_pool_lock);
Florin Coras7baeb712019-01-04 17:05:43 -0800273}
274
Florin Coras0ef8ef22019-01-18 08:37:13 -0800275typedef enum
276{
277 VLS_MT_OP_READ,
278 VLS_MT_OP_WRITE,
279 VLS_MT_OP_SPOOL,
280 VLS_MT_OP_XPOLL,
281} vls_mt_ops_t;
282
283typedef enum
284{
285 VLS_MT_LOCK_MQ = 1 << 0,
286 VLS_MT_LOCK_SPOOL = 1 << 1
287} vls_mt_lock_type_t;
288
Florin Coras0ef8ef22019-01-18 08:37:13 -0800289static void
290vls_mt_add (void)
291{
Florin Coras2d675d72019-01-28 15:54:27 -0800292 vlsl->vls_mt_n_threads += 1;
Florin Corasff40d8f2020-08-11 22:05:28 -0700293
294 /* If multi-thread workers are supported, for each new thread register a new
295 * vcl worker with vpp. Otherwise, all threads use the same vcl worker, so
296 * update the vcl worker's thread local worker index variable */
hanlina3a48962020-07-13 11:09:15 +0800297 if (vls_mt_wrk_supported ())
wanghanlin492350e2020-09-11 17:19:32 +0800298 {
299 if (vppcom_worker_register () != VPPCOM_OK)
300 VERR ("failed to register worker");
301 }
hanlina3a48962020-07-13 11:09:15 +0800302 else
303 vcl_set_worker_index (vlsl->vls_wrk_index);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800304}
305
306static inline void
307vls_mt_mq_lock (void)
308{
Florin Coras2d675d72019-01-28 15:54:27 -0800309 pthread_mutex_lock (&vlsl->vls_mt_mq_mlock);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800310}
311
312static inline void
313vls_mt_mq_unlock (void)
314{
Florin Coras2d675d72019-01-28 15:54:27 -0800315 pthread_mutex_unlock (&vlsl->vls_mt_mq_mlock);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800316}
317
318static inline void
319vls_mt_spool_lock (void)
320{
Florin Coras2d675d72019-01-28 15:54:27 -0800321 pthread_mutex_lock (&vlsl->vls_mt_spool_mlock);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800322}
323
324static inline void
325vls_mt_create_unlock (void)
326{
Florin Coras2d675d72019-01-28 15:54:27 -0800327 pthread_mutex_unlock (&vlsl->vls_mt_spool_mlock);
328}
329
330static void
331vls_mt_locks_init (void)
332{
333 pthread_mutex_init (&vlsl->vls_mt_mq_mlock, NULL);
334 pthread_mutex_init (&vlsl->vls_mt_spool_mlock, NULL);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800335}
336
Florin Coras243edd52020-03-04 22:20:12 +0000337u8
338vls_is_shared (vcl_locked_session_t * vls)
339{
340 return (vls->shared_data_index != ~0);
341}
342
343static inline void
344vls_lock (vcl_locked_session_t * vls)
345{
346 if ((vlsl->vls_mt_n_threads > 1) || vls_is_shared (vls))
347 clib_spinlock_lock (&vls->lock);
348}
349
350static inline void
351vls_unlock (vcl_locked_session_t * vls)
352{
353 if ((vlsl->vls_mt_n_threads > 1) || vls_is_shared (vls))
354 clib_spinlock_unlock (&vls->lock);
355}
356
Florin Coras7baeb712019-01-04 17:05:43 -0800357static inline vcl_session_handle_t
358vls_to_sh (vcl_locked_session_t * vls)
359{
Florin Corasf9240dc2019-01-15 08:03:17 -0800360 return vcl_session_handle_from_index (vls->session_index);
Florin Coras7baeb712019-01-04 17:05:43 -0800361}
362
363static inline vcl_session_handle_t
364vls_to_sh_tu (vcl_locked_session_t * vls)
365{
366 vcl_session_handle_t sh;
367 sh = vls_to_sh (vls);
Florin Coras5e618432021-07-26 18:19:25 -0700368 vls_mt_pool_runlock ();
Florin Coras7baeb712019-01-04 17:05:43 -0800369 return sh;
370}
371
Florin Coras243edd52020-03-04 22:20:12 +0000372static vls_worker_t *
373vls_worker_get_current (void)
374{
375 return pool_elt_at_index (vlsm->workers, vls_get_worker_index ());
376}
377
Mohamed Feroz88c836c2024-08-29 08:04:02 +0000378static inline u8
379vls_n_workers (void)
380{
381 return pool_elts (vlsm->workers);
382}
383
Florin Coras243edd52020-03-04 22:20:12 +0000384static void
385vls_worker_alloc (void)
386{
387 vls_worker_t *wrk;
388
389 pool_get_zero (vlsm->workers, wrk);
wanghanline8f848a2021-01-08 14:57:11 +0800390 if (vls_mt_wrk_supported ())
391 clib_rwlock_init (&wrk->sh_to_vlsh_table_lock);
Florin Coras5e618432021-07-26 18:19:25 -0700392 wrk->vcl_wrk_index = vcl_get_worker_index ();
393 vec_validate (wrk->pending_vcl_wrk_cleanup, 16);
394 vec_reset_length (wrk->pending_vcl_wrk_cleanup);
Florin Coras243edd52020-03-04 22:20:12 +0000395}
396
397static void
398vls_worker_free (vls_worker_t * wrk)
399{
Florin Coras5e618432021-07-26 18:19:25 -0700400 hash_free (wrk->sh_to_vlsh_table);
wanghanline8f848a2021-01-08 14:57:11 +0800401 if (vls_mt_wrk_supported ())
402 clib_rwlock_free (&wrk->sh_to_vlsh_table_lock);
Florin Coras243edd52020-03-04 22:20:12 +0000403 pool_free (wrk->vls_pool);
404 pool_put (vlsm->workers, wrk);
405}
406
407static vls_worker_t *
408vls_worker_get (u32 wrk_index)
409{
410 if (pool_is_free_index (vlsm->workers, wrk_index))
411 return 0;
412 return pool_elt_at_index (vlsm->workers, wrk_index);
413}
414
wanghanline8f848a2021-01-08 14:57:11 +0800415static void
416vls_sh_to_vlsh_table_add (vls_worker_t *wrk, vcl_session_handle_t sh, u32 vlsh)
417{
418 if (vls_mt_wrk_supported ())
419 clib_rwlock_writer_lock (&wrk->sh_to_vlsh_table_lock);
Florin Coras5e618432021-07-26 18:19:25 -0700420 hash_set (wrk->sh_to_vlsh_table, sh, vlsh);
wanghanline8f848a2021-01-08 14:57:11 +0800421 if (vls_mt_wrk_supported ())
422 clib_rwlock_writer_unlock (&wrk->sh_to_vlsh_table_lock);
423}
424
425static void
426vls_sh_to_vlsh_table_del (vls_worker_t *wrk, vcl_session_handle_t sh)
427{
428 if (vls_mt_wrk_supported ())
429 clib_rwlock_writer_lock (&wrk->sh_to_vlsh_table_lock);
Florin Coras5e618432021-07-26 18:19:25 -0700430 hash_unset (wrk->sh_to_vlsh_table, sh);
wanghanline8f848a2021-01-08 14:57:11 +0800431 if (vls_mt_wrk_supported ())
432 clib_rwlock_writer_unlock (&wrk->sh_to_vlsh_table_lock);
433}
434
435static uword *
436vls_sh_to_vlsh_table_get (vls_worker_t *wrk, vcl_session_handle_t sh)
437{
438 if (vls_mt_wrk_supported ())
439 clib_rwlock_reader_lock (&wrk->sh_to_vlsh_table_lock);
Florin Coras5e618432021-07-26 18:19:25 -0700440 uword *vlshp = hash_get (wrk->sh_to_vlsh_table, sh);
wanghanline8f848a2021-01-08 14:57:11 +0800441 if (vls_mt_wrk_supported ())
442 clib_rwlock_reader_unlock (&wrk->sh_to_vlsh_table_lock);
443 return vlshp;
444}
445
Florin Coras7baeb712019-01-04 17:05:43 -0800446static vls_handle_t
447vls_alloc (vcl_session_handle_t sh)
448{
Florin Coras243edd52020-03-04 22:20:12 +0000449 vls_worker_t *wrk = vls_worker_get_current ();
Florin Coras7baeb712019-01-04 17:05:43 -0800450 vcl_locked_session_t *vls;
451
Florin Coras5e618432021-07-26 18:19:25 -0700452 vls_mt_pool_wlock ();
Florin Coras243edd52020-03-04 22:20:12 +0000453
454 pool_get_zero (wrk->vls_pool, vls);
Florin Coras7baeb712019-01-04 17:05:43 -0800455 vls->session_index = vppcom_session_index (sh);
Florin Coras5e618432021-07-26 18:19:25 -0700456 vls->vcl_wrk_index = vppcom_session_worker (sh);
Florin Coras243edd52020-03-04 22:20:12 +0000457 vls->vls_index = vls - wrk->vls_pool;
458 vls->shared_data_index = ~0;
wanghanline8f848a2021-01-08 14:57:11 +0800459 vls_sh_to_vlsh_table_add (wrk, sh, vls->vls_index);
hanlina3a48962020-07-13 11:09:15 +0800460 if (vls_mt_wrk_supported ())
461 {
Florin Coras5e618432021-07-26 18:19:25 -0700462 hash_set (vls->vcl_wrk_index_to_session_index, vls->vcl_wrk_index,
hanlina3a48962020-07-13 11:09:15 +0800463 vls->session_index);
Florin Coras5e618432021-07-26 18:19:25 -0700464 vls->owner_vcl_wrk_index = vls->vcl_wrk_index;
hanlina3a48962020-07-13 11:09:15 +0800465 }
Florin Coras7baeb712019-01-04 17:05:43 -0800466 clib_spinlock_init (&vls->lock);
Florin Coras243edd52020-03-04 22:20:12 +0000467
Florin Coras5e618432021-07-26 18:19:25 -0700468 vls_mt_pool_wunlock ();
Florin Coras7baeb712019-01-04 17:05:43 -0800469 return vls->vls_index;
470}
471
472static vcl_locked_session_t *
473vls_get (vls_handle_t vlsh)
474{
Florin Coras243edd52020-03-04 22:20:12 +0000475 vls_worker_t *wrk = vls_worker_get_current ();
476 if (pool_is_free_index (wrk->vls_pool, vlsh))
Florin Coras7baeb712019-01-04 17:05:43 -0800477 return 0;
Florin Coras243edd52020-03-04 22:20:12 +0000478 return pool_elt_at_index (wrk->vls_pool, vlsh);
Florin Coras7baeb712019-01-04 17:05:43 -0800479}
480
481static void
Florin Coras0ef8ef22019-01-18 08:37:13 -0800482vls_free (vcl_locked_session_t * vls)
Florin Coras7baeb712019-01-04 17:05:43 -0800483{
Florin Coras243edd52020-03-04 22:20:12 +0000484 vls_worker_t *wrk = vls_worker_get_current ();
485
Florin Coras0ef8ef22019-01-18 08:37:13 -0800486 ASSERT (vls != 0);
wanghanline8f848a2021-01-08 14:57:11 +0800487 vls_sh_to_vlsh_table_del (
488 wrk, vcl_session_handle_from_index (vls->session_index));
Florin Coras0ef8ef22019-01-18 08:37:13 -0800489 clib_spinlock_free (&vls->lock);
Florin Coras243edd52020-03-04 22:20:12 +0000490 pool_put (wrk->vls_pool, vls);
Florin Coras7baeb712019-01-04 17:05:43 -0800491}
492
493static vcl_locked_session_t *
494vls_get_and_lock (vls_handle_t vlsh)
495{
Florin Coras243edd52020-03-04 22:20:12 +0000496 vls_worker_t *wrk = vls_worker_get_current ();
Florin Coras7baeb712019-01-04 17:05:43 -0800497 vcl_locked_session_t *vls;
Florin Coras243edd52020-03-04 22:20:12 +0000498 if (pool_is_free_index (wrk->vls_pool, vlsh))
Florin Coras7baeb712019-01-04 17:05:43 -0800499 return 0;
Florin Coras243edd52020-03-04 22:20:12 +0000500 vls = pool_elt_at_index (wrk->vls_pool, vlsh);
501 vls_lock (vls);
Florin Coras7baeb712019-01-04 17:05:43 -0800502 return vls;
503}
504
505static vcl_locked_session_t *
506vls_get_w_dlock (vls_handle_t vlsh)
507{
508 vcl_locked_session_t *vls;
Florin Coras5e618432021-07-26 18:19:25 -0700509 vls_mt_pool_rlock ();
Florin Coras7baeb712019-01-04 17:05:43 -0800510 vls = vls_get_and_lock (vlsh);
511 if (!vls)
Florin Coras5e618432021-07-26 18:19:25 -0700512 vls_mt_pool_runlock ();
Florin Coras7baeb712019-01-04 17:05:43 -0800513 return vls;
514}
515
516static inline void
Florin Coras7baeb712019-01-04 17:05:43 -0800517vls_get_and_unlock (vls_handle_t vlsh)
518{
519 vcl_locked_session_t *vls;
Florin Coras5e618432021-07-26 18:19:25 -0700520 vls_mt_pool_rlock ();
Florin Coras7baeb712019-01-04 17:05:43 -0800521 vls = vls_get (vlsh);
522 vls_unlock (vls);
Florin Coras5e618432021-07-26 18:19:25 -0700523 vls_mt_pool_runlock ();
Florin Coras7baeb712019-01-04 17:05:43 -0800524}
525
526static inline void
527vls_dunlock (vcl_locked_session_t * vls)
528{
529 vls_unlock (vls);
Florin Coras5e618432021-07-26 18:19:25 -0700530 vls_mt_pool_runlock ();
Florin Coras7baeb712019-01-04 17:05:43 -0800531}
532
Florin Coras243edd52020-03-04 22:20:12 +0000533static vcl_locked_session_t *
534vls_session_get (vls_worker_t * wrk, u32 vls_index)
535{
536 if (pool_is_free_index (wrk->vls_pool, vls_index))
537 return 0;
538 return pool_elt_at_index (wrk->vls_pool, vls_index);
539}
540
Florin Coras2d675d72019-01-28 15:54:27 -0800541vcl_session_handle_t
542vlsh_to_sh (vls_handle_t vlsh)
543{
544 vcl_locked_session_t *vls;
545 int rv;
546
547 vls = vls_get_w_dlock (vlsh);
548 if (!vls)
549 return INVALID_SESSION_ID;
550 rv = vls_to_sh (vls);
551 vls_dunlock (vls);
552 return rv;
553}
554
555vcl_session_handle_t
556vlsh_to_session_index (vls_handle_t vlsh)
557{
558 vcl_session_handle_t sh;
559 sh = vlsh_to_sh (vlsh);
560 return vppcom_session_index (sh);
561}
562
Florin Corasce4635c2024-10-23 14:19:31 -0700563int
564vlsh_to_worker_index (vls_handle_t vlsh)
565{
566 vcl_locked_session_t *vls;
567 u32 wrk_index;
568
569 vls = vls_get_w_dlock (vlsh);
570 if (!vls)
571 wrk_index = INVALID_SESSION_ID;
572 else
573 wrk_index = vls->vcl_wrk_index;
574 vls_dunlock (vls);
575
576 return wrk_index;
577}
578
Florin Coras2d675d72019-01-28 15:54:27 -0800579vls_handle_t
hanlinf8e13632020-08-21 11:05:36 +0800580vls_si_wi_to_vlsh (u32 session_index, u32 vcl_wrk_index)
Florin Coras2d675d72019-01-28 15:54:27 -0800581{
Florin Coras243edd52020-03-04 22:20:12 +0000582 vls_worker_t *wrk = vls_worker_get_current ();
wanghanline8f848a2021-01-08 14:57:11 +0800583 uword *vlshp = vls_sh_to_vlsh_table_get (
584 wrk,
585 vcl_session_handle_from_wrk_session_index (session_index, vcl_wrk_index));
586
Florin Coras2d675d72019-01-28 15:54:27 -0800587 return vlshp ? *vlshp : VLS_INVALID_HANDLE;
588}
589
590vls_handle_t
591vls_session_index_to_vlsh (uint32_t session_index)
592{
593 vls_handle_t vlsh;
594
Florin Coras5e618432021-07-26 18:19:25 -0700595 vls_mt_pool_rlock ();
hanlinf8e13632020-08-21 11:05:36 +0800596 vlsh = vls_si_wi_to_vlsh (session_index, vcl_get_worker_index ());
Florin Coras5e618432021-07-26 18:19:25 -0700597 vls_mt_pool_runlock ();
Florin Coras2d675d72019-01-28 15:54:27 -0800598
599 return vlsh;
600}
601
Florin Corasf9240dc2019-01-15 08:03:17 -0800602u8
Florin Coras0ef8ef22019-01-18 08:37:13 -0800603vls_is_shared_by_wrk (vcl_locked_session_t * vls, u32 wrk_index)
Florin Corasf9240dc2019-01-15 08:03:17 -0800604{
Florin Coras243edd52020-03-04 22:20:12 +0000605 vls_shared_data_t *vls_shd;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800606 int i;
Florin Coras243edd52020-03-04 22:20:12 +0000607
608 if (vls->shared_data_index == ~0)
609 return 0;
610
611 vls_shared_data_pool_rlock ();
612
613 vls_shd = vls_shared_data_get (vls->shared_data_index);
614 clib_spinlock_lock (&vls_shd->lock);
615
616 for (i = 0; i < vec_len (vls_shd->workers_subscribed); i++)
617 if (vls_shd->workers_subscribed[i] == wrk_index)
618 {
619 clib_spinlock_unlock (&vls_shd->lock);
620 vls_shared_data_pool_runlock ();
621 return 1;
622 }
623 clib_spinlock_unlock (&vls_shd->lock);
624
625 vls_shared_data_pool_runlock ();
Florin Coras0ef8ef22019-01-18 08:37:13 -0800626 return 0;
627}
628
Florin Coras2d675d72019-01-28 15:54:27 -0800629static void
630vls_listener_wrk_set (vcl_locked_session_t * vls, u32 wrk_index, u8 is_active)
631{
Florin Coras243edd52020-03-04 22:20:12 +0000632 vls_shared_data_t *vls_shd;
633
634 if (vls->shared_data_index == ~0)
635 {
636 clib_warning ("not a shared session");
637 return;
638 }
639
640 vls_shared_data_pool_rlock ();
641
642 vls_shd = vls_shared_data_get (vls->shared_data_index);
643
644 clib_spinlock_lock (&vls_shd->lock);
Florin Coras674d5652021-12-03 23:02:13 -0800645 vls_shd->listeners =
646 clib_bitmap_set (vls_shd->listeners, wrk_index, is_active);
Florin Coras243edd52020-03-04 22:20:12 +0000647 clib_spinlock_unlock (&vls_shd->lock);
648
649 vls_shared_data_pool_runlock ();
650}
651
652static u32
653vls_shared_get_owner (vcl_locked_session_t * vls)
654{
655 vls_shared_data_t *vls_shd;
656 u32 owner_wrk;
657
658 vls_shared_data_pool_rlock ();
659
660 vls_shd = vls_shared_data_get (vls->shared_data_index);
661 owner_wrk = vls_shd->owner_wrk_index;
662
663 vls_shared_data_pool_runlock ();
664
665 return owner_wrk;
Florin Coras2d675d72019-01-28 15:54:27 -0800666}
667
668static u8
669vls_listener_wrk_is_active (vcl_locked_session_t * vls, u32 wrk_index)
670{
Florin Coras243edd52020-03-04 22:20:12 +0000671 vls_shared_data_t *vls_shd;
672 u8 is_set;
673
674 if (vls->shared_data_index == ~0)
675 {
676 clib_warning ("not a shared session");
677 return 0;
678 }
679
680 vls_shared_data_pool_rlock ();
681
682 vls_shd = vls_shared_data_get (vls->shared_data_index);
683
684 clib_spinlock_lock (&vls_shd->lock);
685 is_set = clib_bitmap_get (vls_shd->listeners, wrk_index);
686 clib_spinlock_unlock (&vls_shd->lock);
687
688 vls_shared_data_pool_runlock ();
689
690 return (is_set == 1);
Florin Coras2d675d72019-01-28 15:54:27 -0800691}
692
693static void
694vls_listener_wrk_start_listen (vcl_locked_session_t * vls, u32 wrk_index)
695{
Florin Coras32881932023-02-06 13:30:13 -0800696 vcl_worker_t *wrk;
697 vcl_session_t *ls;
698
699 wrk = vcl_worker_get (wrk_index);
700 ls = vcl_session_get (wrk, vls->session_index);
701
702 /* Listen request already sent */
703 if (ls->flags & VCL_SESSION_F_PENDING_LISTEN)
704 return;
705
706 vcl_send_session_listen (wrk, ls);
707
708 vls_listener_wrk_set (vls, wrk_index, 1 /* is_active */);
Florin Coras2d675d72019-01-28 15:54:27 -0800709}
710
711static void
712vls_listener_wrk_stop_listen (vcl_locked_session_t * vls, u32 wrk_index)
713{
714 vcl_worker_t *wrk;
715 vcl_session_t *s;
716
717 wrk = vcl_worker_get (wrk_index);
718 s = vcl_session_get (wrk, vls->session_index);
Florin Corasc127d5a2020-10-14 16:35:58 -0700719 if (s->session_state != VCL_STATE_LISTEN)
Florin Coras2d675d72019-01-28 15:54:27 -0800720 return;
Florin Coras458089b2019-08-21 16:20:44 -0700721 vcl_send_session_unlisten (wrk, s);
Florin Corasc127d5a2020-10-14 16:35:58 -0700722 s->session_state = VCL_STATE_LISTEN_NO_MQ;
Florin Coras2d675d72019-01-28 15:54:27 -0800723 vls_listener_wrk_set (vls, wrk_index, 0 /* is_active */ );
724}
725
Florin Coras243edd52020-03-04 22:20:12 +0000726static int
727vls_shared_data_subscriber_position (vls_shared_data_t * vls_shd,
728 u32 wrk_index)
729{
730 int i;
731
732 for (i = 0; i < vec_len (vls_shd->workers_subscribed); i++)
733 {
734 if (vls_shd->workers_subscribed[i] == wrk_index)
735 return i;
736 }
737 return -1;
738}
739
Florin Coras0ef8ef22019-01-18 08:37:13 -0800740int
741vls_unshare_session (vcl_locked_session_t * vls, vcl_worker_t * wrk)
742{
Florin Coras243edd52020-03-04 22:20:12 +0000743 vls_shared_data_t *vls_shd;
Florin Coras311817f2020-03-07 17:45:47 +0000744 int do_disconnect, pos;
745 u32 n_subscribers;
Florin Corasf9240dc2019-01-15 08:03:17 -0800746 vcl_session_t *s;
Florin Coras2d675d72019-01-28 15:54:27 -0800747
hanlina3a48962020-07-13 11:09:15 +0800748 if (vls->shared_data_index == ~0)
749 return 0;
Florin Coras243edd52020-03-04 22:20:12 +0000750
Florin Coras2d675d72019-01-28 15:54:27 -0800751 s = vcl_session_get (wrk, vls->session_index);
Florin Corasc127d5a2020-10-14 16:35:58 -0700752 if (s->session_state == VCL_STATE_LISTEN)
Florin Coras2d675d72019-01-28 15:54:27 -0800753 vls_listener_wrk_set (vls, wrk->wrk_index, 0 /* is_active */ );
Florin Corasf9240dc2019-01-15 08:03:17 -0800754
Florin Coras243edd52020-03-04 22:20:12 +0000755 vls_shared_data_pool_rlock ();
Florin Corasf9240dc2019-01-15 08:03:17 -0800756
Florin Coras243edd52020-03-04 22:20:12 +0000757 vls_shd = vls_shared_data_get (vls->shared_data_index);
758 clib_spinlock_lock (&vls_shd->lock);
759
760 pos = vls_shared_data_subscriber_position (vls_shd, wrk->wrk_index);
761 if (pos < 0)
762 {
763 clib_warning ("worker %u not subscribed for vls %u", wrk->wrk_index,
Florin Coras5e618432021-07-26 18:19:25 -0700764 vls->vcl_wrk_index);
Florin Coras243edd52020-03-04 22:20:12 +0000765 goto done;
766 }
767
768 /*
769 * Unsubscribe from share data and fifos
770 */
771 if (s->rx_fifo)
772 {
773 svm_fifo_del_subscriber (s->rx_fifo, wrk->vpp_wrk_index);
774 svm_fifo_del_subscriber (s->tx_fifo, wrk->vpp_wrk_index);
775 }
776 vec_del1 (vls_shd->workers_subscribed, pos);
777
778 /*
779 * Cleanup vcl state
780 */
781 n_subscribers = vec_len (vls_shd->workers_subscribed);
Florin Corasc127d5a2020-10-14 16:35:58 -0700782 do_disconnect = s->session_state == VCL_STATE_LISTEN || !n_subscribers;
Florin Coras243edd52020-03-04 22:20:12 +0000783 vcl_session_cleanup (wrk, s, vcl_session_handle (s), do_disconnect);
784
785 /*
786 * No subscriber left, cleanup shared data
787 */
788 if (!n_subscribers)
789 {
790 u32 shd_index = vls_shared_data_index (vls_shd);
791
792 clib_spinlock_unlock (&vls_shd->lock);
793 vls_shared_data_pool_runlock ();
794
795 vls_shared_data_free (shd_index);
796
797 /* All locks have been dropped */
Florin Corasf9240dc2019-01-15 08:03:17 -0800798 return 0;
799 }
800
Florin Coras0ef8ef22019-01-18 08:37:13 -0800801 /* Return, if this is not the owning worker */
Florin Coras243edd52020-03-04 22:20:12 +0000802 if (vls_shd->owner_wrk_index != wrk->wrk_index)
803 goto done;
Florin Coras0ef8ef22019-01-18 08:37:13 -0800804
Florin Coras243edd52020-03-04 22:20:12 +0000805 ASSERT (vec_len (vls_shd->workers_subscribed));
806
807 /*
808 * Check if we can change owner or close
809 */
810 vls_shd->owner_wrk_index = vls_shd->workers_subscribed[0];
liuyacan603e1a42021-07-22 15:52:01 +0800811 if (s->vpp_evt_q)
liuyacan5cac2e82021-07-14 15:53:01 +0800812 vcl_send_session_worker_update (wrk, s, vls_shd->owner_wrk_index);
Florin Coras243edd52020-03-04 22:20:12 +0000813
814 /* XXX is this still needed? */
815 if (vec_len (vls_shd->workers_subscribed) > 1)
816 clib_warning ("more workers need to be updated");
817
818done:
819
820 clib_spinlock_unlock (&vls_shd->lock);
821 vls_shared_data_pool_runlock ();
Florin Corasf9240dc2019-01-15 08:03:17 -0800822
823 return 0;
824}
825
826void
Florin Coras40c07ce2020-07-16 20:46:17 -0700827vls_init_share_session (vls_worker_t * vls_wrk, vcl_locked_session_t * vls)
Florin Corasf9240dc2019-01-15 08:03:17 -0800828{
Florin Coras40c07ce2020-07-16 20:46:17 -0700829 vls_shared_data_t *vls_shd;
830
831 u32 vls_shd_index = vls_shared_data_alloc ();
832
833 vls_shared_data_pool_rlock ();
834
835 vls_shd = vls_shared_data_get (vls_shd_index);
Florin Coras5e618432021-07-26 18:19:25 -0700836 vls_shd->owner_wrk_index = vls_wrk->vcl_wrk_index;
Florin Coras40c07ce2020-07-16 20:46:17 -0700837 vls->shared_data_index = vls_shd_index;
Florin Coras5e618432021-07-26 18:19:25 -0700838 vec_add1 (vls_shd->workers_subscribed, vls_wrk->vcl_wrk_index);
Florin Coras40c07ce2020-07-16 20:46:17 -0700839
840 vls_shared_data_pool_runlock ();
841}
842
843void
844vls_share_session (vls_worker_t * vls_wrk, vcl_locked_session_t * vls)
845{
Florin Coras5e618432021-07-26 18:19:25 -0700846 vcl_worker_t *vcl_wrk = vcl_worker_get (vls_wrk->vcl_wrk_index);
Florin Coras243edd52020-03-04 22:20:12 +0000847 vls_shared_data_t *vls_shd;
848 vcl_session_t *s;
Florin Corasf9240dc2019-01-15 08:03:17 -0800849
Florin Coras243edd52020-03-04 22:20:12 +0000850 s = vcl_session_get (vcl_wrk, vls->session_index);
851 if (!s)
852 {
Florin Coras40c07ce2020-07-16 20:46:17 -0700853 clib_warning ("wrk %u session %u vls %u NOT AVAILABLE",
854 vcl_wrk->wrk_index, vls->session_index, vls->vls_index);
Florin Coras243edd52020-03-04 22:20:12 +0000855 return;
856 }
857
Florin Coras40c07ce2020-07-16 20:46:17 -0700858 ASSERT (vls->shared_data_index != ~0);
859
Florin Coras243edd52020-03-04 22:20:12 +0000860 /* Reinit session lock */
861 clib_spinlock_init (&vls->lock);
862
Florin Coras40c07ce2020-07-16 20:46:17 -0700863 vls_shared_data_pool_rlock ();
Florin Coras243edd52020-03-04 22:20:12 +0000864
Florin Coras40c07ce2020-07-16 20:46:17 -0700865 vls_shd = vls_shared_data_get (vls->shared_data_index);
Florin Coras243edd52020-03-04 22:20:12 +0000866
867 clib_spinlock_lock (&vls_shd->lock);
Florin Coras5e618432021-07-26 18:19:25 -0700868 vec_add1 (vls_shd->workers_subscribed, vls_wrk->vcl_wrk_index);
Florin Coras243edd52020-03-04 22:20:12 +0000869 clib_spinlock_unlock (&vls_shd->lock);
Florin Coras40c07ce2020-07-16 20:46:17 -0700870
Florin Coras243edd52020-03-04 22:20:12 +0000871 vls_shared_data_pool_runlock ();
872
Florin Coras7428eaa2023-12-11 16:04:57 -0800873 if (s->session_state == VCL_STATE_LISTEN)
Florin Coras2d675d72019-01-28 15:54:27 -0800874 {
Florin Corasc127d5a2020-10-14 16:35:58 -0700875 s->session_state = VCL_STATE_LISTEN_NO_MQ;
Florin Coras7428eaa2023-12-11 16:04:57 -0800876 s->rx_fifo = s->tx_fifo = 0;
877 }
878 else if (s->rx_fifo)
879 {
880 vcl_session_share_fifos (s, s->rx_fifo, s->tx_fifo);
Florin Coras2d675d72019-01-28 15:54:27 -0800881 }
Florin Coras243edd52020-03-04 22:20:12 +0000882}
Florin Coras2d675d72019-01-28 15:54:27 -0800883
Florin Coras243edd52020-03-04 22:20:12 +0000884static void
885vls_share_sessions (vls_worker_t * vls_parent_wrk, vls_worker_t * vls_wrk)
886{
Florin Coras40c07ce2020-07-16 20:46:17 -0700887 vcl_locked_session_t *vls, *parent_vls;
Florin Coras243edd52020-03-04 22:20:12 +0000888
Damjan Marionb2c31b62020-12-13 21:47:40 +0100889 pool_foreach (vls, vls_wrk->vls_pool) {
Florin Coras40c07ce2020-07-16 20:46:17 -0700890 /* Initialize sharing on parent session */
891 if (vls->shared_data_index == ~0)
892 {
893 parent_vls = vls_session_get (vls_parent_wrk, vls->vls_index);
894 vls_init_share_session (vls_parent_wrk, parent_vls);
895 vls->shared_data_index = parent_vls->shared_data_index;
896 }
897 vls_share_session (vls_wrk, vls);
Damjan Marionb2c31b62020-12-13 21:47:40 +0100898 }
Florin Corasf9240dc2019-01-15 08:03:17 -0800899}
900
wanghanlin5788a342021-06-22 17:34:08 +0800901static void
902vls_validate_veps (vcl_worker_t *wrk)
903{
904 vcl_session_t *s;
905 u32 session_index, wrk_index;
906
907 pool_foreach (s, wrk->sessions)
908 {
909 if (s->vep.vep_sh != ~0)
910 {
911 vcl_session_handle_parse (s->vep.vep_sh, &wrk_index, &session_index);
912 s->vep.vep_sh = vcl_session_handle_from_index (session_index);
913 }
914 if (s->vep.next_sh != ~0)
915 {
916 vcl_session_handle_parse (s->vep.next_sh, &wrk_index,
917 &session_index);
918 s->vep.next_sh = vcl_session_handle_from_index (session_index);
919 }
920 if (s->vep.prev_sh != ~0)
921 {
922 vcl_session_handle_parse (s->vep.prev_sh, &wrk_index,
923 &session_index);
924 s->vep.prev_sh = vcl_session_handle_from_index (session_index);
925 }
926 }
927}
928
Florin Corasf9240dc2019-01-15 08:03:17 -0800929void
930vls_worker_copy_on_fork (vcl_worker_t * parent_wrk)
931{
Florin Coras243edd52020-03-04 22:20:12 +0000932 vls_worker_t *vls_wrk = vls_worker_get_current (), *vls_parent_wrk;
Florin Coras5e618432021-07-26 18:19:25 -0700933 vcl_worker_t *vcl_wrk = vcl_worker_get_current ();
hanlinf8e13632020-08-21 11:05:36 +0800934 u32 vls_index, session_index, wrk_index;
935 vcl_session_handle_t sh;
liuyacan603e1a42021-07-22 15:52:01 +0800936 vcl_locked_session_t *vls;
Florin Corasf9240dc2019-01-15 08:03:17 -0800937
Florin Coras243edd52020-03-04 22:20:12 +0000938 /*
939 * init vcl worker
940 */
Florin Coras5e618432021-07-26 18:19:25 -0700941 vcl_wrk->sessions = pool_dup (parent_wrk->sessions);
942 vcl_wrk->session_index_by_vpp_handles =
Florin Corasf9240dc2019-01-15 08:03:17 -0800943 hash_dup (parent_wrk->session_index_by_vpp_handles);
944
Florin Coras243edd52020-03-04 22:20:12 +0000945 /*
946 * init vls worker
947 */
948 vls_parent_wrk = vls_worker_get (parent_wrk->wrk_index);
Florin Coras5e618432021-07-26 18:19:25 -0700949
950 /* clang-format off */
951 hash_foreach (sh, vls_index, vls_parent_wrk->sh_to_vlsh_table, ({
952 vcl_session_handle_parse (sh, &wrk_index, &session_index);
953 hash_set (vls_wrk->sh_to_vlsh_table,
954 vcl_session_handle_from_index (session_index), vls_index);
955 }));
956 /* clang-format on */
Florin Coras243edd52020-03-04 22:20:12 +0000957 vls_wrk->vls_pool = pool_dup (vls_parent_wrk->vls_pool);
Florin Coras2d675d72019-01-28 15:54:27 -0800958
liuyacan603e1a42021-07-22 15:52:01 +0800959 /*
960 * Detach vls from parent vcl worker and attach them to child.
961 */
962 pool_foreach (vls, vls_wrk->vls_pool)
963 {
Florin Coras5e618432021-07-26 18:19:25 -0700964 vls->vcl_wrk_index = vcl_wrk->wrk_index;
liuyacan603e1a42021-07-22 15:52:01 +0800965 }
966
wanghanlin5788a342021-06-22 17:34:08 +0800967 /* Validate vep's handle */
Florin Coras5e618432021-07-26 18:19:25 -0700968 vls_validate_veps (vcl_wrk);
wanghanlin5788a342021-06-22 17:34:08 +0800969
Florin Coras243edd52020-03-04 22:20:12 +0000970 vls_share_sessions (vls_parent_wrk, vls_wrk);
Florin Corasf9240dc2019-01-15 08:03:17 -0800971}
972
Florin Coras0ef8ef22019-01-18 08:37:13 -0800973static void
974vls_mt_acq_locks (vcl_locked_session_t * vls, vls_mt_ops_t op, int *locks_acq)
975{
976 vcl_worker_t *wrk = vcl_worker_get_current ();
977 vcl_session_t *s = 0;
978 int is_nonblk = 0;
979
980 if (vls)
981 {
982 s = vcl_session_get (wrk, vls->session_index);
983 if (PREDICT_FALSE (!s))
984 return;
Florin Corasac422d62020-10-19 20:51:36 -0700985 is_nonblk = vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK);
Florin Coras0ef8ef22019-01-18 08:37:13 -0800986 }
987
988 switch (op)
989 {
990 case VLS_MT_OP_READ:
991 if (!is_nonblk)
992 is_nonblk = vcl_session_read_ready (s) != 0;
993 if (!is_nonblk)
994 {
995 vls_mt_mq_lock ();
996 *locks_acq |= VLS_MT_LOCK_MQ;
997 }
998 break;
999 case VLS_MT_OP_WRITE:
Florin Coras78b5fa62019-02-21 20:04:15 -08001000 ASSERT (s);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001001 if (!is_nonblk)
1002 is_nonblk = vcl_session_write_ready (s) != 0;
1003 if (!is_nonblk)
1004 {
1005 vls_mt_mq_lock ();
1006 *locks_acq |= VLS_MT_LOCK_MQ;
1007 }
1008 break;
1009 case VLS_MT_OP_XPOLL:
1010 vls_mt_mq_lock ();
1011 *locks_acq |= VLS_MT_LOCK_MQ;
1012 break;
1013 case VLS_MT_OP_SPOOL:
1014 vls_mt_spool_lock ();
1015 *locks_acq |= VLS_MT_LOCK_SPOOL;
1016 break;
1017 default:
1018 break;
1019 }
1020}
1021
1022static void
1023vls_mt_rel_locks (int locks_acq)
1024{
1025 if (locks_acq & VLS_MT_LOCK_MQ)
1026 vls_mt_mq_unlock ();
1027 if (locks_acq & VLS_MT_LOCK_SPOOL)
1028 vls_mt_create_unlock ();
1029}
1030
Florin Corasff40d8f2020-08-11 22:05:28 -07001031static inline u8
1032vls_mt_session_should_migrate (vcl_locked_session_t * vls)
1033{
Florin Coras5e618432021-07-26 18:19:25 -07001034 return (vls_mt_wrk_supported () &&
1035 vls->vcl_wrk_index != vcl_get_worker_index ());
Florin Corasff40d8f2020-08-11 22:05:28 -07001036}
1037
wanghanlindcacdc42020-12-28 16:19:05 +08001038static vcl_locked_session_t *
1039vls_mt_session_migrate (vcl_locked_session_t *vls)
hanlina3a48962020-07-13 11:09:15 +08001040{
1041 u32 wrk_index = vcl_get_worker_index ();
1042 vcl_worker_t *wrk;
wanghanline8f848a2021-01-08 14:57:11 +08001043 vls_worker_t *vls_wrk = vls_worker_get_current ();
wanghanlindcacdc42020-12-28 16:19:05 +08001044 u32 src_sid, sid, vls_index, own_vcl_wrk_index;
hanlina3a48962020-07-13 11:09:15 +08001045 vcl_session_t *session;
1046 uword *p;
1047
Florin Coras5e618432021-07-26 18:19:25 -07001048 ASSERT (vls_mt_wrk_supported () && vls->vcl_wrk_index != wrk_index);
hanlina3a48962020-07-13 11:09:15 +08001049
Florin Corasff40d8f2020-08-11 22:05:28 -07001050 /*
1051 * VCL session on current vcl worker already allocated. Update current
1052 * owner worker and index and return
1053 */
hanlina3a48962020-07-13 11:09:15 +08001054 if ((p = hash_get (vls->vcl_wrk_index_to_session_index, wrk_index)))
1055 {
Florin Coras5e618432021-07-26 18:19:25 -07001056 vls->vcl_wrk_index = wrk_index;
hanlina3a48962020-07-13 11:09:15 +08001057 vls->session_index = (u32) p[0];
wanghanlindcacdc42020-12-28 16:19:05 +08001058 return vls;
hanlina3a48962020-07-13 11:09:15 +08001059 }
1060
Florin Corasff40d8f2020-08-11 22:05:28 -07001061 /*
1062 * Ask vcl worker that owns the original vcl session to clone it into
1063 * current vcl worker session pool
1064 */
1065
hanlina3a48962020-07-13 11:09:15 +08001066 if (!(p = hash_get (vls->vcl_wrk_index_to_session_index,
1067 vls->owner_vcl_wrk_index)))
1068 {
1069 VERR ("session in owner worker(%u) is free", vls->owner_vcl_wrk_index);
1070 ASSERT (0);
wanghanlindcacdc42020-12-28 16:19:05 +08001071 vls_unlock (vls);
Florin Coras5e618432021-07-26 18:19:25 -07001072 vls_mt_pool_runlock ();
wanghanlindcacdc42020-12-28 16:19:05 +08001073 return 0;
hanlina3a48962020-07-13 11:09:15 +08001074 }
1075
1076 src_sid = (u32) p[0];
1077 wrk = vcl_worker_get_current ();
1078 session = vcl_session_alloc (wrk);
1079 sid = session->session_index;
hanlina3a48962020-07-13 11:09:15 +08001080 VDBG (1, "migrate session of worker (session): %u (%u) -> %u (%u)",
1081 vls->owner_vcl_wrk_index, src_sid, wrk_index, sid);
1082
wanghanlindcacdc42020-12-28 16:19:05 +08001083 /* Drop lock to prevent dead lock when dst wrk trying to get lock. */
1084 vls_index = vls->vls_index;
1085 own_vcl_wrk_index = vls->owner_vcl_wrk_index;
1086 vls_unlock (vls);
Florin Coras5e618432021-07-26 18:19:25 -07001087 vls_mt_pool_runlock ();
wanghanlindcacdc42020-12-28 16:19:05 +08001088 vls_send_clone_and_share_rpc (wrk, vls_index, sid, vls_get_worker_index (),
1089 own_vcl_wrk_index, vls_index, src_sid);
1090
1091 if (PREDICT_FALSE (wrk->rpc_done == VLS_RPC_STATE_SESSION_NOT_EXIST))
hanlina3a48962020-07-13 11:09:15 +08001092 {
wanghanlindcacdc42020-12-28 16:19:05 +08001093 VWRN ("session %u not exist", src_sid);
1094 goto err;
1095 }
1096 else if (PREDICT_FALSE (wrk->rpc_done == VLS_RPC_STATE_INIT))
1097 {
1098 VWRN ("failed to wait rpc response");
1099 goto err;
1100 }
1101 else if (PREDICT_FALSE ((session->flags & VCL_SESSION_F_IS_VEP) &&
1102 session->vep.next_sh != ~0))
1103 {
hanlina3a48962020-07-13 11:09:15 +08001104 VERR ("can't migrate nonempty epoll session");
1105 ASSERT (0);
wanghanlindcacdc42020-12-28 16:19:05 +08001106 goto err;
hanlina3a48962020-07-13 11:09:15 +08001107 }
Florin Coras6c3b2182020-10-19 18:36:48 -07001108 else if (PREDICT_FALSE (!(session->flags & VCL_SESSION_F_IS_VEP) &&
Florin Corasc127d5a2020-10-14 16:35:58 -07001109 session->session_state != VCL_STATE_CLOSED))
hanlina3a48962020-07-13 11:09:15 +08001110 {
hanlina3a48962020-07-13 11:09:15 +08001111 VERR ("migrate NOT supported, session_status (%u)",
1112 session->session_state);
1113 ASSERT (0);
wanghanlindcacdc42020-12-28 16:19:05 +08001114 goto err;
hanlina3a48962020-07-13 11:09:15 +08001115 }
wanghanlindcacdc42020-12-28 16:19:05 +08001116
1117 vls = vls_get_w_dlock (vls_index);
1118 if (PREDICT_FALSE (!vls))
1119 {
1120 VWRN ("failed to get vls %u", vls_index);
1121 goto err;
1122 }
1123
1124 session->session_index = sid;
Florin Coras5e618432021-07-26 18:19:25 -07001125 vls->vcl_wrk_index = wrk_index;
wanghanlindcacdc42020-12-28 16:19:05 +08001126 vls->session_index = sid;
1127 hash_set (vls->vcl_wrk_index_to_session_index, wrk_index, sid);
wanghanline8f848a2021-01-08 14:57:11 +08001128 vls_sh_to_vlsh_table_add (vls_wrk, vcl_session_handle (session),
1129 vls->vls_index);
wanghanlindcacdc42020-12-28 16:19:05 +08001130 return vls;
1131
1132err:
1133 vcl_session_free (wrk, session);
1134 return 0;
hanlina3a48962020-07-13 11:09:15 +08001135}
1136
Florin Corasff40d8f2020-08-11 22:05:28 -07001137static inline void
1138vls_mt_detect (void)
1139{
1140 if (PREDICT_FALSE (vcl_get_worker_index () == ~0))
1141 vls_mt_add ();
1142}
Florin Coras0ef8ef22019-01-18 08:37:13 -08001143
wanghanlindcacdc42020-12-28 16:19:05 +08001144#define vls_mt_guard(_vls, _op) \
1145 int _locks_acq = 0; \
1146 if (vls_mt_wrk_supported ()) \
1147 { \
1148 if (PREDICT_FALSE (_vls && \
Florin Coras5e618432021-07-26 18:19:25 -07001149 ((vcl_locked_session_t *) _vls)->vcl_wrk_index != \
wanghanlindcacdc42020-12-28 16:19:05 +08001150 vcl_get_worker_index ())) \
1151 { \
1152 _vls = vls_mt_session_migrate (_vls); \
1153 if (PREDICT_FALSE (!_vls)) \
1154 return VPPCOM_EBADFD; \
1155 } \
1156 } \
1157 else \
1158 { \
1159 if (PREDICT_FALSE (vlsl->vls_mt_n_threads > 1)) \
1160 vls_mt_acq_locks (_vls, _op, &_locks_acq); \
1161 }
Florin Corasff40d8f2020-08-11 22:05:28 -07001162
1163#define vls_mt_unguard() \
1164 if (PREDICT_FALSE (_locks_acq)) \
Florin Coras0ef8ef22019-01-18 08:37:13 -08001165 vls_mt_rel_locks (_locks_acq)
1166
Florin Coras7baeb712019-01-04 17:05:43 -08001167int
1168vls_write (vls_handle_t vlsh, void *buf, size_t nbytes)
1169{
1170 vcl_locked_session_t *vls;
1171 int rv;
1172
Florin Corasff40d8f2020-08-11 22:05:28 -07001173 vls_mt_detect ();
Florin Coras7baeb712019-01-04 17:05:43 -08001174 if (!(vls = vls_get_w_dlock (vlsh)))
1175 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -08001176
1177 vls_mt_guard (vls, VLS_MT_OP_WRITE);
Florin Coras7baeb712019-01-04 17:05:43 -08001178 rv = vppcom_session_write (vls_to_sh_tu (vls), buf, nbytes);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001179 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -08001180 vls_get_and_unlock (vlsh);
1181 return rv;
1182}
1183
1184int
1185vls_write_msg (vls_handle_t vlsh, void *buf, size_t nbytes)
1186{
1187 vcl_locked_session_t *vls;
1188 int rv;
1189
Florin Corasff40d8f2020-08-11 22:05:28 -07001190 vls_mt_detect ();
Florin Coras7baeb712019-01-04 17:05:43 -08001191 if (!(vls = vls_get_w_dlock (vlsh)))
1192 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -08001193 vls_mt_guard (vls, VLS_MT_OP_WRITE);
Florin Coras7baeb712019-01-04 17:05:43 -08001194 rv = vppcom_session_write_msg (vls_to_sh_tu (vls), buf, nbytes);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001195 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -08001196 vls_get_and_unlock (vlsh);
1197 return rv;
1198}
1199
1200int
1201vls_sendto (vls_handle_t vlsh, void *buf, int buflen, int flags,
1202 vppcom_endpt_t * ep)
1203{
1204 vcl_locked_session_t *vls;
1205 int rv;
1206
Florin Corasff40d8f2020-08-11 22:05:28 -07001207 vls_mt_detect ();
Florin Coras7baeb712019-01-04 17:05:43 -08001208 if (!(vls = vls_get_w_dlock (vlsh)))
1209 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -08001210 vls_mt_guard (vls, VLS_MT_OP_WRITE);
Florin Coras7baeb712019-01-04 17:05:43 -08001211 rv = vppcom_session_sendto (vls_to_sh_tu (vls), buf, buflen, flags, ep);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001212 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -08001213 vls_get_and_unlock (vlsh);
1214 return rv;
1215}
1216
1217ssize_t
1218vls_read (vls_handle_t vlsh, void *buf, size_t nbytes)
1219{
1220 vcl_locked_session_t *vls;
1221 int rv;
1222
Florin Corasff40d8f2020-08-11 22:05:28 -07001223 vls_mt_detect ();
Florin Coras7baeb712019-01-04 17:05:43 -08001224 if (!(vls = vls_get_w_dlock (vlsh)))
1225 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -08001226 vls_mt_guard (vls, VLS_MT_OP_READ);
Florin Coras7baeb712019-01-04 17:05:43 -08001227 rv = vppcom_session_read (vls_to_sh_tu (vls), buf, nbytes);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001228 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -08001229 vls_get_and_unlock (vlsh);
1230 return rv;
1231}
1232
1233ssize_t
1234vls_recvfrom (vls_handle_t vlsh, void *buffer, uint32_t buflen, int flags,
1235 vppcom_endpt_t * ep)
1236{
1237 vcl_locked_session_t *vls;
1238 int rv;
1239
Florin Corasff40d8f2020-08-11 22:05:28 -07001240 vls_mt_detect ();
Florin Coras7baeb712019-01-04 17:05:43 -08001241 if (!(vls = vls_get_w_dlock (vlsh)))
1242 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -08001243 vls_mt_guard (vls, VLS_MT_OP_READ);
Florin Coras7baeb712019-01-04 17:05:43 -08001244 rv = vppcom_session_recvfrom (vls_to_sh_tu (vls), buffer, buflen, flags,
1245 ep);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001246 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -08001247 vls_get_and_unlock (vlsh);
1248 return rv;
1249}
1250
1251int
1252vls_attr (vls_handle_t vlsh, uint32_t op, void *buffer, uint32_t * buflen)
1253{
1254 vcl_locked_session_t *vls;
1255 int rv;
1256
Florin Corasff40d8f2020-08-11 22:05:28 -07001257 vls_mt_detect ();
Florin Coras7baeb712019-01-04 17:05:43 -08001258 if (!(vls = vls_get_w_dlock (vlsh)))
1259 return VPPCOM_EBADFD;
Florin Corasff40d8f2020-08-11 22:05:28 -07001260 if (vls_mt_session_should_migrate (vls))
wanghanlindcacdc42020-12-28 16:19:05 +08001261 {
1262 vls = vls_mt_session_migrate (vls);
1263 if (PREDICT_FALSE (!vls))
1264 return VPPCOM_EBADFD;
1265 }
Florin Coras7baeb712019-01-04 17:05:43 -08001266 rv = vppcom_session_attr (vls_to_sh_tu (vls), op, buffer, buflen);
1267 vls_get_and_unlock (vlsh);
1268 return rv;
1269}
1270
1271int
1272vls_bind (vls_handle_t vlsh, vppcom_endpt_t * ep)
1273{
1274 vcl_locked_session_t *vls;
1275 int rv;
1276
Florin Corasff40d8f2020-08-11 22:05:28 -07001277 vls_mt_detect ();
Florin Coras7baeb712019-01-04 17:05:43 -08001278 if (!(vls = vls_get_w_dlock (vlsh)))
1279 return VPPCOM_EBADFD;
1280 rv = vppcom_session_bind (vls_to_sh_tu (vls), ep);
1281 vls_get_and_unlock (vlsh);
1282 return rv;
1283}
1284
1285int
1286vls_listen (vls_handle_t vlsh, int q_len)
1287{
1288 vcl_locked_session_t *vls;
1289 int rv;
1290
Florin Corasff40d8f2020-08-11 22:05:28 -07001291 vls_mt_detect ();
Florin Coras7baeb712019-01-04 17:05:43 -08001292 if (!(vls = vls_get_w_dlock (vlsh)))
1293 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -08001294 vls_mt_guard (vls, VLS_MT_OP_XPOLL);
Florin Coras7baeb712019-01-04 17:05:43 -08001295 rv = vppcom_session_listen (vls_to_sh_tu (vls), q_len);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001296 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -08001297 vls_get_and_unlock (vlsh);
1298 return rv;
1299}
1300
1301int
1302vls_connect (vls_handle_t vlsh, vppcom_endpt_t * server_ep)
1303{
1304 vcl_locked_session_t *vls;
1305 int rv;
1306
Florin Corasff40d8f2020-08-11 22:05:28 -07001307 vls_mt_detect ();
Florin Coras7baeb712019-01-04 17:05:43 -08001308 if (!(vls = vls_get_w_dlock (vlsh)))
1309 return VPPCOM_EBADFD;
Florin Coras0ef8ef22019-01-18 08:37:13 -08001310 vls_mt_guard (vls, VLS_MT_OP_XPOLL);
Florin Coras7baeb712019-01-04 17:05:43 -08001311 rv = vppcom_session_connect (vls_to_sh_tu (vls), server_ep);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001312 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -08001313 vls_get_and_unlock (vlsh);
1314 return rv;
1315}
1316
Florin Coras2d675d72019-01-28 15:54:27 -08001317static inline void
1318vls_mp_checks (vcl_locked_session_t * vls, int is_add)
1319{
1320 vcl_worker_t *wrk = vcl_worker_get_current ();
1321 vcl_session_t *s;
Florin Coras243edd52020-03-04 22:20:12 +00001322 u32 owner_wrk;
Florin Coras2d675d72019-01-28 15:54:27 -08001323
Mohamed Feroz88c836c2024-08-29 08:04:02 +00001324 if (vls_mt_wrk_supported () && vls_n_workers () <= 1)
hanlina3a48962020-07-13 11:09:15 +08001325 return;
1326
Florin Coras5e618432021-07-26 18:19:25 -07001327 ASSERT (wrk->wrk_index == vls->vcl_wrk_index);
Florin Coras2d675d72019-01-28 15:54:27 -08001328 s = vcl_session_get (wrk, vls->session_index);
1329 switch (s->session_state)
1330 {
Florin Corasc127d5a2020-10-14 16:35:58 -07001331 case VCL_STATE_LISTEN:
Florin Coras2d675d72019-01-28 15:54:27 -08001332 if (is_add)
1333 {
Florin Coras5e618432021-07-26 18:19:25 -07001334 vls_listener_wrk_set (vls, vls->vcl_wrk_index, 1 /* is_active */);
Florin Coras2d675d72019-01-28 15:54:27 -08001335 break;
1336 }
Florin Corasa41a0b52023-03-01 22:22:30 -08001337 /* Although removal from epoll means listener no longer accepts new
1338 * sessions, the accept queue built by vpp cannot be drained by stopping
1339 * the listener. Morover, some applications, e.g., nginx, might
1340 * constantly remove and add listeners to their epfds. Removing
1341 * listeners in such situations causes a lot of churn in vpp as segments
1342 * and segment managers need to be recreated. */
1343 /* vls_listener_wrk_stop_listen (vls, vls->vcl_wrk_index); */
Florin Coras2d675d72019-01-28 15:54:27 -08001344 break;
Florin Corasc127d5a2020-10-14 16:35:58 -07001345 case VCL_STATE_LISTEN_NO_MQ:
Florin Coras2d675d72019-01-28 15:54:27 -08001346 if (!is_add)
1347 break;
1348
1349 /* Register worker as listener */
Florin Coras5e618432021-07-26 18:19:25 -07001350 vls_listener_wrk_start_listen (vls, vls->vcl_wrk_index);
Florin Coras2d675d72019-01-28 15:54:27 -08001351
1352 /* If owner worker did not attempt to accept/xpoll on the session,
1353 * force a listen stop for it, since it may not be interested in
1354 * accepting new sessions.
1355 * This is pretty much a hack done to give app workers the illusion
1356 * that it is fine to listen and not accept new sessions for a
1357 * given listener. Without it, we would accumulate unhandled
1358 * accepts on the passive worker message queue. */
Florin Coras243edd52020-03-04 22:20:12 +00001359 owner_wrk = vls_shared_get_owner (vls);
1360 if (!vls_listener_wrk_is_active (vls, owner_wrk))
1361 vls_listener_wrk_stop_listen (vls, owner_wrk);
Florin Coras2d675d72019-01-28 15:54:27 -08001362 break;
1363 default:
1364 break;
1365 }
1366}
1367
Florin Coras7baeb712019-01-04 17:05:43 -08001368vls_handle_t
1369vls_accept (vls_handle_t listener_vlsh, vppcom_endpt_t * ep, int flags)
1370{
1371 vls_handle_t accepted_vlsh;
1372 vcl_locked_session_t *vls;
1373 int sh;
1374
Florin Corasff40d8f2020-08-11 22:05:28 -07001375 vls_mt_detect ();
Florin Coras7baeb712019-01-04 17:05:43 -08001376 if (!(vls = vls_get_w_dlock (listener_vlsh)))
1377 return VPPCOM_EBADFD;
Florin Coras2d675d72019-01-28 15:54:27 -08001378 if (vcl_n_workers () > 1)
1379 vls_mp_checks (vls, 1 /* is_add */ );
Florin Coras0ef8ef22019-01-18 08:37:13 -08001380 vls_mt_guard (vls, VLS_MT_OP_SPOOL);
Florin Coras7baeb712019-01-04 17:05:43 -08001381 sh = vppcom_session_accept (vls_to_sh_tu (vls), ep, flags);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001382 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -08001383 vls_get_and_unlock (listener_vlsh);
1384 if (sh < 0)
1385 return sh;
1386 accepted_vlsh = vls_alloc (sh);
1387 if (PREDICT_FALSE (accepted_vlsh == VLS_INVALID_HANDLE))
1388 vppcom_session_close (sh);
1389 return accepted_vlsh;
1390}
1391
1392vls_handle_t
1393vls_create (uint8_t proto, uint8_t is_nonblocking)
1394{
1395 vcl_session_handle_t sh;
1396 vls_handle_t vlsh;
wanghanlindcacdc42020-12-28 16:19:05 +08001397 vcl_locked_session_t *vls = NULL;
Florin Coras7baeb712019-01-04 17:05:43 -08001398
Florin Corasff40d8f2020-08-11 22:05:28 -07001399 vls_mt_detect ();
wanghanlindcacdc42020-12-28 16:19:05 +08001400 vls_mt_guard (vls, VLS_MT_OP_SPOOL);
Florin Coras7baeb712019-01-04 17:05:43 -08001401 sh = vppcom_session_create (proto, is_nonblocking);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001402 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -08001403 if (sh == INVALID_SESSION_ID)
1404 return VLS_INVALID_HANDLE;
1405
1406 vlsh = vls_alloc (sh);
1407 if (PREDICT_FALSE (vlsh == VLS_INVALID_HANDLE))
1408 vppcom_session_close (sh);
1409
1410 return vlsh;
1411}
1412
hanlina3a48962020-07-13 11:09:15 +08001413static void
Florin Corasff40d8f2020-08-11 22:05:28 -07001414vls_mt_session_cleanup (vcl_locked_session_t * vls)
hanlina3a48962020-07-13 11:09:15 +08001415{
Florin Corasff40d8f2020-08-11 22:05:28 -07001416 u32 session_index, wrk_index, current_vcl_wrk;
hanlina3a48962020-07-13 11:09:15 +08001417 vcl_worker_t *wrk = vcl_worker_get_current ();
1418
Florin Corasff40d8f2020-08-11 22:05:28 -07001419 ASSERT (vls_mt_wrk_supported ());
1420
1421 current_vcl_wrk = vcl_get_worker_index ();
hanlina3a48962020-07-13 11:09:15 +08001422
hanlina3a48962020-07-13 11:09:15 +08001423 hash_foreach (wrk_index, session_index, vls->vcl_wrk_index_to_session_index,
1424 ({
Florin Corasff40d8f2020-08-11 22:05:28 -07001425 if (current_vcl_wrk != wrk_index)
1426 vls_send_session_cleanup_rpc (wrk, wrk_index, session_index);
hanlina3a48962020-07-13 11:09:15 +08001427 }));
hanlina3a48962020-07-13 11:09:15 +08001428 hash_free (vls->vcl_wrk_index_to_session_index);
1429}
1430
Florin Coras7baeb712019-01-04 17:05:43 -08001431int
1432vls_close (vls_handle_t vlsh)
1433{
1434 vcl_locked_session_t *vls;
Florin Corasf9240dc2019-01-15 08:03:17 -08001435 int rv;
Florin Coras7baeb712019-01-04 17:05:43 -08001436
Florin Corasff40d8f2020-08-11 22:05:28 -07001437 vls_mt_detect ();
Florin Coras5e618432021-07-26 18:19:25 -07001438 vls_mt_pool_wlock ();
Florin Coras7baeb712019-01-04 17:05:43 -08001439
Florin Coras0ef8ef22019-01-18 08:37:13 -08001440 vls = vls_get_and_lock (vlsh);
1441 if (!vls)
1442 {
Florin Coras5e618432021-07-26 18:19:25 -07001443 vls_mt_pool_wunlock ();
Florin Coras0ef8ef22019-01-18 08:37:13 -08001444 return VPPCOM_EBADFD;
1445 }
1446
hanlina3a48962020-07-13 11:09:15 +08001447 vls_mt_guard (vls, VLS_MT_OP_SPOOL);
Florin Corasf9240dc2019-01-15 08:03:17 -08001448
Florin Coras243edd52020-03-04 22:20:12 +00001449 if (vls_is_shared (vls))
1450 rv = vls_unshare_session (vls, vcl_worker_get_current ());
1451 else
1452 rv = vppcom_session_close (vls_to_sh (vls));
1453
Florin Corasff40d8f2020-08-11 22:05:28 -07001454 if (vls_mt_wrk_supported ())
1455 vls_mt_session_cleanup (vls);
hanlina3a48962020-07-13 11:09:15 +08001456
Florin Coras0ef8ef22019-01-18 08:37:13 -08001457 vls_free (vls);
1458 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -08001459
Florin Coras5e618432021-07-26 18:19:25 -07001460 vls_mt_pool_wunlock ();
Florin Coras0ef8ef22019-01-18 08:37:13 -08001461
Florin Coras7baeb712019-01-04 17:05:43 -08001462 return rv;
1463}
1464
liuyacan534468e2021-05-09 03:50:40 +00001465int
liuyacan55c952e2021-06-13 14:54:55 +08001466vls_shutdown (vls_handle_t vlsh, int how)
liuyacan534468e2021-05-09 03:50:40 +00001467{
1468 vcl_locked_session_t *vls;
1469 int rv;
1470
1471 vls_mt_detect ();
1472 if (!(vls = vls_get_w_dlock (vlsh)))
1473 return VPPCOM_EBADFD;
1474
1475 vls_mt_guard (vls, VLS_MT_OP_SPOOL);
liuyacan6fc07b42021-07-24 22:48:36 +08001476 rv = vppcom_session_shutdown (vls_to_sh_tu (vls), how);
liuyacan534468e2021-05-09 03:50:40 +00001477 vls_mt_unguard ();
1478 vls_get_and_unlock (vlsh);
1479
1480 return rv;
1481}
1482
Florin Coras7baeb712019-01-04 17:05:43 -08001483vls_handle_t
1484vls_epoll_create (void)
1485{
1486 vcl_session_handle_t sh;
1487 vls_handle_t vlsh;
1488
Florin Corasff40d8f2020-08-11 22:05:28 -07001489 vls_mt_detect ();
Florin Coras63d3ac62019-03-29 08:29:25 -07001490
Florin Coras7baeb712019-01-04 17:05:43 -08001491 sh = vppcom_epoll_create ();
1492 if (sh == INVALID_SESSION_ID)
1493 return VLS_INVALID_HANDLE;
1494
1495 vlsh = vls_alloc (sh);
1496 if (vlsh == VLS_INVALID_HANDLE)
1497 vppcom_session_close (sh);
1498
1499 return vlsh;
1500}
1501
Florin Coras2d675d72019-01-28 15:54:27 -08001502static void
1503vls_epoll_ctl_mp_checks (vcl_locked_session_t * vls, int op)
1504{
nandfandc2632e2021-03-26 16:46:58 +08001505 if (vcl_n_workers () <= 1 || op == EPOLL_CTL_MOD)
Florin Coras2d675d72019-01-28 15:54:27 -08001506 return;
1507
Florin Coras2d675d72019-01-28 15:54:27 -08001508 vls_mp_checks (vls, op == EPOLL_CTL_ADD);
1509}
1510
Florin Coras7baeb712019-01-04 17:05:43 -08001511int
1512vls_epoll_ctl (vls_handle_t ep_vlsh, int op, vls_handle_t vlsh,
1513 struct epoll_event *event)
1514{
1515 vcl_locked_session_t *ep_vls, *vls;
1516 vcl_session_handle_t ep_sh, sh;
1517 int rv;
1518
Florin Corasff40d8f2020-08-11 22:05:28 -07001519 vls_mt_detect ();
Florin Coras5e618432021-07-26 18:19:25 -07001520 vls_mt_pool_rlock ();
Florin Coras54223ee2022-03-02 21:06:30 -08001521
Florin Coras7baeb712019-01-04 17:05:43 -08001522 ep_vls = vls_get_and_lock (ep_vlsh);
Florin Coras54223ee2022-03-02 21:06:30 -08001523 if (PREDICT_FALSE (!ep_vls))
1524 {
1525 vls_mt_pool_runlock ();
1526 return VPPCOM_EBADFD;
1527 }
Florin Corasff40d8f2020-08-11 22:05:28 -07001528
1529 if (vls_mt_session_should_migrate (ep_vls))
wanghanlindcacdc42020-12-28 16:19:05 +08001530 {
1531 ep_vls = vls_mt_session_migrate (ep_vls);
1532 if (PREDICT_FALSE (!ep_vls))
Florin Coras54223ee2022-03-02 21:06:30 -08001533 {
1534 vls_mt_pool_runlock ();
1535 return VPPCOM_EBADFD;
1536 }
1537 }
1538
1539 vls = vls_get_and_lock (vlsh);
1540 if (PREDICT_FALSE (!vls))
1541 {
1542 vls_unlock (ep_vls);
1543 vls_mt_pool_runlock ();
1544 return VPPCOM_EBADFD;
wanghanlindcacdc42020-12-28 16:19:05 +08001545 }
Florin Corasff40d8f2020-08-11 22:05:28 -07001546
Florin Coras7baeb712019-01-04 17:05:43 -08001547 ep_sh = vls_to_sh (ep_vls);
1548 sh = vls_to_sh (vls);
Florin Coras2d675d72019-01-28 15:54:27 -08001549
nandfandc2632e2021-03-26 16:46:58 +08001550 vls_epoll_ctl_mp_checks (vls, op);
Florin Coras5e618432021-07-26 18:19:25 -07001551 vls_mt_pool_runlock ();
Florin Coras7baeb712019-01-04 17:05:43 -08001552 rv = vppcom_epoll_ctl (ep_sh, op, sh, event);
1553
Florin Coras5e618432021-07-26 18:19:25 -07001554 vls_mt_pool_rlock ();
Florin Coras7baeb712019-01-04 17:05:43 -08001555 ep_vls = vls_get (ep_vlsh);
1556 vls = vls_get (vlsh);
1557 vls_unlock (vls);
1558 vls_unlock (ep_vls);
Florin Coras5e618432021-07-26 18:19:25 -07001559 vls_mt_pool_runlock ();
Florin Coras7baeb712019-01-04 17:05:43 -08001560 return rv;
1561}
1562
1563int
1564vls_epoll_wait (vls_handle_t ep_vlsh, struct epoll_event *events,
1565 int maxevents, double wait_for_time)
1566{
wanghanlindcacdc42020-12-28 16:19:05 +08001567 vcl_locked_session_t *vls, *vls_tmp = NULL;
Florin Coras7baeb712019-01-04 17:05:43 -08001568 int rv;
1569
Florin Corasff40d8f2020-08-11 22:05:28 -07001570 vls_mt_detect ();
Florin Coras7baeb712019-01-04 17:05:43 -08001571 if (!(vls = vls_get_w_dlock (ep_vlsh)))
1572 return VPPCOM_EBADFD;
wanghanlindcacdc42020-12-28 16:19:05 +08001573 vls_mt_guard (vls_tmp, VLS_MT_OP_XPOLL);
Florin Coras7baeb712019-01-04 17:05:43 -08001574 rv = vppcom_epoll_wait (vls_to_sh_tu (vls), events, maxevents,
1575 wait_for_time);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001576 vls_mt_unguard ();
Florin Coras7baeb712019-01-04 17:05:43 -08001577 vls_get_and_unlock (ep_vlsh);
wanghanlind72a0342021-05-12 17:00:29 +08001578 vls_handle_pending_wrk_cleanup ();
Florin Coras7baeb712019-01-04 17:05:43 -08001579 return rv;
1580}
1581
Florin Coras2d675d72019-01-28 15:54:27 -08001582static void
1583vls_select_mp_checks (vcl_si_set * read_map)
1584{
1585 vcl_locked_session_t *vls;
1586 vcl_worker_t *wrk;
1587 vcl_session_t *s;
1588 u32 si;
1589
1590 if (vcl_n_workers () <= 1)
1591 {
1592 vlsl->select_mp_check = 1;
1593 return;
1594 }
1595
1596 if (!read_map)
1597 return;
1598
1599 vlsl->select_mp_check = 1;
1600 wrk = vcl_worker_get_current ();
1601
Damjan Marionf0ca1e82020-12-13 23:26:56 +01001602 clib_bitmap_foreach (si, read_map) {
Florin Coras2d675d72019-01-28 15:54:27 -08001603 s = vcl_session_get (wrk, si);
Florin Corasc127d5a2020-10-14 16:35:58 -07001604 if (s->session_state == VCL_STATE_LISTEN)
Florin Coras2d675d72019-01-28 15:54:27 -08001605 {
1606 vls = vls_get (vls_session_index_to_vlsh (si));
1607 vls_mp_checks (vls, 1 /* is_add */);
1608 }
Damjan Marionf0ca1e82020-12-13 23:26:56 +01001609 }
Florin Coras2d675d72019-01-28 15:54:27 -08001610}
1611
Florin Coras0ef8ef22019-01-18 08:37:13 -08001612int
1613vls_select (int n_bits, vcl_si_set * read_map, vcl_si_set * write_map,
1614 vcl_si_set * except_map, double wait_for_time)
1615{
1616 int rv;
wanghanlindcacdc42020-12-28 16:19:05 +08001617 vcl_locked_session_t *vls = NULL;
Florin Coras2d675d72019-01-28 15:54:27 -08001618
Florin Corasff40d8f2020-08-11 22:05:28 -07001619 vls_mt_detect ();
wanghanlindcacdc42020-12-28 16:19:05 +08001620 vls_mt_guard (vls, VLS_MT_OP_XPOLL);
Florin Coras2d675d72019-01-28 15:54:27 -08001621 if (PREDICT_FALSE (!vlsl->select_mp_check))
1622 vls_select_mp_checks (read_map);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001623 rv = vppcom_select (n_bits, read_map, write_map, except_map, wait_for_time);
1624 vls_mt_unguard ();
wanghanlind72a0342021-05-12 17:00:29 +08001625 vls_handle_pending_wrk_cleanup ();
Florin Coras0ef8ef22019-01-18 08:37:13 -08001626 return rv;
1627}
1628
Florin Corasf9240dc2019-01-15 08:03:17 -08001629static void
Florin Coras0ef8ef22019-01-18 08:37:13 -08001630vls_unshare_vcl_worker_sessions (vcl_worker_t * wrk)
1631{
1632 u32 current_wrk, is_current;
1633 vcl_locked_session_t *vls;
1634 vcl_session_t *s;
1635
Florin Coras14ed6df2019-03-06 21:13:42 -08001636 if (pool_elts (vcm->workers) <= 1)
1637 return;
1638
Florin Coras0ef8ef22019-01-18 08:37:13 -08001639 current_wrk = vcl_get_worker_index ();
1640 is_current = current_wrk == wrk->wrk_index;
Florin Coras0ef8ef22019-01-18 08:37:13 -08001641
Damjan Marionb2c31b62020-12-13 21:47:40 +01001642 pool_foreach (s, wrk->sessions) {
hanlinf8e13632020-08-21 11:05:36 +08001643 vls = vls_get (vls_si_wi_to_vlsh (s->session_index, wrk->wrk_index));
Florin Coras0ef8ef22019-01-18 08:37:13 -08001644 if (vls && (is_current || vls_is_shared_by_wrk (vls, current_wrk)))
1645 vls_unshare_session (vls, wrk);
Damjan Marionb2c31b62020-12-13 21:47:40 +01001646 }
Florin Coras0ef8ef22019-01-18 08:37:13 -08001647}
1648
1649static void
1650vls_cleanup_vcl_worker (vcl_worker_t * wrk)
1651{
Florin Coras243edd52020-03-04 22:20:12 +00001652 vls_worker_t *vls_wrk = vls_worker_get (wrk->wrk_index);
1653
Florin Coras0ef8ef22019-01-18 08:37:13 -08001654 /* Unshare sessions and also cleanup worker since child may have
1655 * called _exit () and therefore vcl may not catch the event */
1656 vls_unshare_vcl_worker_sessions (wrk);
wanghanlinb940fd42021-06-29 16:01:55 +08001657
1658 /* Since child may have exited and thereforce fd of vpp_app_socket_api
1659 * may have been closed, so DONOT notify VPP.
1660 */
1661 vcl_worker_cleanup (wrk, vcm->cfg.vpp_app_socket_api ? 0 : 1);
Florin Coras243edd52020-03-04 22:20:12 +00001662
1663 vls_worker_free (vls_wrk);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001664}
1665
1666static void
Florin Corasf9240dc2019-01-15 08:03:17 -08001667vls_cleanup_forked_child (vcl_worker_t * wrk, vcl_worker_t * child_wrk)
1668{
1669 vcl_worker_t *sub_child;
1670 int tries = 0;
1671
1672 if (child_wrk->forked_child != ~0)
1673 {
1674 sub_child = vcl_worker_get_if_valid (child_wrk->forked_child);
1675 if (sub_child)
1676 {
1677 /* Wait a bit, maybe the process is going away */
1678 while (kill (sub_child->current_pid, 0) >= 0 && tries++ < 50)
1679 usleep (1e3);
1680 if (kill (sub_child->current_pid, 0) < 0)
1681 vls_cleanup_forked_child (child_wrk, sub_child);
1682 }
1683 }
Florin Coras0ef8ef22019-01-18 08:37:13 -08001684 vls_cleanup_vcl_worker (child_wrk);
1685 VDBG (0, "Cleaned up forked child wrk %u", child_wrk->wrk_index);
Florin Corasf9240dc2019-01-15 08:03:17 -08001686 wrk->forked_child = ~0;
1687}
1688
wanghanlind72a0342021-05-12 17:00:29 +08001689static void
1690vls_handle_pending_wrk_cleanup (void)
1691{
1692 u32 *wip;
1693 vcl_worker_t *child_wrk, *wrk;
1694 vls_worker_t *vls_wrk = vls_worker_get_current ();
1695
Florin Coras5e618432021-07-26 18:19:25 -07001696 if (PREDICT_TRUE (vec_len (vls_wrk->pending_vcl_wrk_cleanup) == 0))
wanghanlind72a0342021-05-12 17:00:29 +08001697 return;
1698
1699 wrk = vcl_worker_get_current ();
Florin Coras5e618432021-07-26 18:19:25 -07001700 vec_foreach (wip, vls_wrk->pending_vcl_wrk_cleanup)
wanghanlind72a0342021-05-12 17:00:29 +08001701 {
1702 child_wrk = vcl_worker_get_if_valid (*wip);
1703 if (!child_wrk)
1704 continue;
1705 vls_cleanup_forked_child (wrk, child_wrk);
1706 }
Florin Coras5e618432021-07-26 18:19:25 -07001707 vec_reset_length (vls_wrk->pending_vcl_wrk_cleanup);
wanghanlind72a0342021-05-12 17:00:29 +08001708}
1709
Florin Corasf9240dc2019-01-15 08:03:17 -08001710static struct sigaction old_sa;
1711
1712static void
1713vls_intercept_sigchld_handler (int signum, siginfo_t * si, void *uc)
1714{
1715 vcl_worker_t *wrk, *child_wrk;
wanghanlind72a0342021-05-12 17:00:29 +08001716 vls_worker_t *vls_wrk;
Florin Corasf9240dc2019-01-15 08:03:17 -08001717
1718 if (vcl_get_worker_index () == ~0)
1719 return;
1720
1721 if (sigaction (SIGCHLD, &old_sa, 0))
1722 {
1723 VERR ("couldn't restore sigchld");
1724 exit (-1);
1725 }
1726
1727 wrk = vcl_worker_get_current ();
1728 if (wrk->forked_child == ~0)
1729 return;
1730
1731 child_wrk = vcl_worker_get_if_valid (wrk->forked_child);
1732 if (!child_wrk)
1733 goto done;
1734
1735 if (si && si->si_pid != child_wrk->current_pid)
1736 {
1737 VDBG (0, "unexpected child pid %u", si->si_pid);
1738 goto done;
1739 }
wanghanlind72a0342021-05-12 17:00:29 +08001740
1741 /* Parent process may enter sighandler with a lock, such as lock in localtime
1742 * or in mspace_free, and child wrk cleanup may try to get such locks and
1743 * cause deadlock.
1744 * So move child wrk cleanup from sighandler to vls_epoll_wait/vls_select.
1745 */
1746 vls_wrk = vls_worker_get_current ();
Florin Coras5e618432021-07-26 18:19:25 -07001747 vec_add1 (vls_wrk->pending_vcl_wrk_cleanup, child_wrk->wrk_index);
Florin Corasf9240dc2019-01-15 08:03:17 -08001748
1749done:
1750 if (old_sa.sa_flags & SA_SIGINFO)
1751 {
1752 void (*fn) (int, siginfo_t *, void *) = old_sa.sa_sigaction;
1753 fn (signum, si, uc);
1754 }
1755 else
1756 {
1757 void (*fn) (int) = old_sa.sa_handler;
1758 if (fn)
1759 fn (signum);
1760 }
1761}
1762
1763static void
1764vls_incercept_sigchld ()
1765{
1766 struct sigaction sa;
nandfan5fdc47c2021-02-22 17:17:17 +08001767 if (old_sa.sa_sigaction)
1768 {
1769 VDBG (0, "have intercepted sigchld");
1770 return;
1771 }
Florin Corasf9240dc2019-01-15 08:03:17 -08001772 clib_memset (&sa, 0, sizeof (sa));
1773 sa.sa_sigaction = vls_intercept_sigchld_handler;
1774 sa.sa_flags = SA_SIGINFO;
1775 if (sigaction (SIGCHLD, &sa, &old_sa))
1776 {
1777 VERR ("couldn't intercept sigchld");
1778 exit (-1);
1779 }
1780}
1781
1782static void
1783vls_app_pre_fork (void)
1784{
1785 vls_incercept_sigchld ();
1786 vcl_flush_mq_events ();
1787}
1788
1789static void
1790vls_app_fork_child_handler (void)
1791{
1792 vcl_worker_t *parent_wrk;
Florin Corasb88de902020-09-08 16:47:57 -07001793 int parent_wrk_index;
Florin Corasf9240dc2019-01-15 08:03:17 -08001794
1795 parent_wrk_index = vcl_get_worker_index ();
1796 VDBG (0, "initializing forked child %u with parent wrk %u", getpid (),
1797 parent_wrk_index);
1798
1799 /*
Florin Corasb88de902020-09-08 16:47:57 -07001800 * Clear old state
Florin Corasf9240dc2019-01-15 08:03:17 -08001801 */
1802 vcl_set_worker_index (~0);
Florin Corasf9240dc2019-01-15 08:03:17 -08001803
1804 /*
Florin Corasb88de902020-09-08 16:47:57 -07001805 * Allocate and register vcl worker with vpp
Florin Corasf9240dc2019-01-15 08:03:17 -08001806 */
Florin Corasb88de902020-09-08 16:47:57 -07001807 if (vppcom_worker_register ())
Florin Corasf9240dc2019-01-15 08:03:17 -08001808 {
Florin Corasb88de902020-09-08 16:47:57 -07001809 VERR ("couldn't register new worker!");
Florin Corasf9240dc2019-01-15 08:03:17 -08001810 return;
1811 }
1812
1813 /*
Florin Corasb88de902020-09-08 16:47:57 -07001814 * Allocate/initialize vls worker and share sessions
Florin Coras243edd52020-03-04 22:20:12 +00001815 */
1816 vls_worker_alloc ();
Florin Corasf9240dc2019-01-15 08:03:17 -08001817
Florin Coras0ef8ef22019-01-18 08:37:13 -08001818 /* Reset number of threads and set wrk index */
Florin Corasce4635c2024-10-23 14:19:31 -07001819 vlsl->vls_mt_n_threads = 1;
Florin Coras2d675d72019-01-28 15:54:27 -08001820 vlsl->vls_wrk_index = vcl_get_worker_index ();
1821 vlsl->select_mp_check = 0;
Florin Coras2e2f9df2021-07-27 22:48:05 -07001822 clib_rwlock_init (&vlsl->vls_pool_lock);
Florin Coras2d675d72019-01-28 15:54:27 -08001823 vls_mt_locks_init ();
Florin Coras0ef8ef22019-01-18 08:37:13 -08001824
liuyacan603e1a42021-07-22 15:52:01 +08001825 parent_wrk = vcl_worker_get (parent_wrk_index);
1826 vls_worker_copy_on_fork (parent_wrk);
1827 parent_wrk->forked_child = vcl_get_worker_index ();
1828
Florin Corasf9240dc2019-01-15 08:03:17 -08001829 VDBG (0, "forked child main worker initialized");
1830 vcm->forking = 0;
1831}
1832
1833static void
1834vls_app_fork_parent_handler (void)
1835{
1836 vcm->forking = 1;
1837 while (vcm->forking)
1838 ;
1839}
1840
Florin Coras0ef8ef22019-01-18 08:37:13 -08001841void
1842vls_app_exit (void)
1843{
Florin Coras243edd52020-03-04 22:20:12 +00001844 vls_worker_t *wrk = vls_worker_get_current ();
1845
wanghanlind72a0342021-05-12 17:00:29 +08001846 /* Handle pending wrk cleanup */
1847 vls_handle_pending_wrk_cleanup ();
1848
Florin Coras0ef8ef22019-01-18 08:37:13 -08001849 /* Unshare the sessions. VCL will clean up the worker */
1850 vls_unshare_vcl_worker_sessions (vcl_worker_get_current ());
Florin Coras243edd52020-03-04 22:20:12 +00001851 vls_worker_free (wrk);
Florin Coras0ef8ef22019-01-18 08:37:13 -08001852}
1853
Florin Coras40c07ce2020-07-16 20:46:17 -07001854static void
1855vls_clone_and_share_rpc_handler (void *args)
1856{
1857 vls_clone_and_share_msg_t *msg = (vls_clone_and_share_msg_t *) args;
1858 vls_worker_t *wrk = vls_worker_get_current (), *dst_wrk;
1859 vcl_locked_session_t *vls, *dst_vls;
hanlina3a48962020-07-13 11:09:15 +08001860 vcl_worker_t *vcl_wrk = vcl_worker_get_current (), *dst_vcl_wrk;
Florin Coras40c07ce2020-07-16 20:46:17 -07001861 vcl_session_t *s, *dst_s;
1862
wanghanlindcacdc42020-12-28 16:19:05 +08001863 VDBG (1, "process session clone of worker (session): %u (%u) -> %u (%u)",
1864 vcl_wrk->wrk_index, msg->session_index, msg->origin_vcl_wrk,
1865 msg->origin_session_index);
1866
1867 /* VCL locked session can't been protected, so DONT touch it.
1868 * VCL session may been free, check it.
1869 */
1870 dst_vcl_wrk = vcl_worker_get (msg->origin_vcl_wrk);
1871 s = vcl_session_get (vcl_wrk, msg->session_index);
1872 if (PREDICT_FALSE (!s))
1873 {
1874 dst_vcl_wrk->rpc_done = VLS_RPC_STATE_SESSION_NOT_EXIST;
1875 return;
1876 }
Florin Coras40c07ce2020-07-16 20:46:17 -07001877
hanlina3a48962020-07-13 11:09:15 +08001878 if (!vls_mt_wrk_supported ())
wanghanlindcacdc42020-12-28 16:19:05 +08001879 {
1880 vls = vls_session_get (wrk, msg->vls_index);
1881 vls_init_share_session (wrk, vls);
1882 dst_wrk = vls_worker_get (msg->origin_vls_wrk);
1883 dst_vls = vls_session_get (dst_wrk, msg->origin_vls_index);
1884 dst_vls->shared_data_index = vls->shared_data_index;
1885 }
hanlina3a48962020-07-13 11:09:15 +08001886 dst_s = vcl_session_get (dst_vcl_wrk, msg->origin_session_index);
Florin Coras40c07ce2020-07-16 20:46:17 -07001887 clib_memcpy (dst_s, s, sizeof (*s));
1888
wanghanlindcacdc42020-12-28 16:19:05 +08001889 dst_vcl_wrk->rpc_done = VLS_RPC_STATE_SUCCESS;
hanlina3a48962020-07-13 11:09:15 +08001890}
1891
1892static void
1893vls_session_cleanup_rpc_handler (void *args)
1894{
1895 vls_sess_cleanup_msg_t *msg = (vls_sess_cleanup_msg_t *) args;
1896 vcl_worker_t *wrk = vcl_worker_get_current ();
wanghanline8f848a2021-01-08 14:57:11 +08001897 vls_worker_t *vls_wrk = vls_worker_get_current ();
wanghanlindcacdc42020-12-28 16:19:05 +08001898 vcl_session_handle_t sh = vcl_session_handle_from_index (msg->session_index);
hanlina3a48962020-07-13 11:09:15 +08001899
wanghanlindcacdc42020-12-28 16:19:05 +08001900 VDBG (1, "process session cleanup of worker (session): %u (%u) from %u ()",
1901 wrk->wrk_index, msg->session_index, msg->origin_vcl_wrk);
hanlina3a48962020-07-13 11:09:15 +08001902
wanghanlindcacdc42020-12-28 16:19:05 +08001903 vppcom_session_close (sh);
wanghanline8f848a2021-01-08 14:57:11 +08001904 vls_sh_to_vlsh_table_del (vls_wrk, sh);
Florin Coras40c07ce2020-07-16 20:46:17 -07001905}
1906
1907static void
1908vls_rpc_handler (void *args)
1909{
1910 vls_rpc_msg_t *msg = (vls_rpc_msg_t *) args;
1911 switch (msg->type)
1912 {
1913 case VLS_RPC_CLONE_AND_SHARE:
1914 vls_clone_and_share_rpc_handler (msg->data);
1915 break;
hanlina3a48962020-07-13 11:09:15 +08001916 case VLS_RPC_SESS_CLEANUP:
1917 vls_session_cleanup_rpc_handler (msg->data);
1918 break;
Florin Coras40c07ce2020-07-16 20:46:17 -07001919 default:
1920 break;
1921 }
1922}
1923
1924void
wanghanlindcacdc42020-12-28 16:19:05 +08001925vls_send_clone_and_share_rpc (vcl_worker_t *wrk, u32 origin_vls_index,
1926 u32 session_index, u32 vls_wrk_index,
1927 u32 dst_wrk_index, u32 dst_vls_index,
1928 u32 dst_session_index)
Florin Coras40c07ce2020-07-16 20:46:17 -07001929{
1930 u8 data[sizeof (u8) + sizeof (vls_clone_and_share_msg_t)];
1931 vls_clone_and_share_msg_t *msg;
1932 vls_rpc_msg_t *rpc;
hanlina3a48962020-07-13 11:09:15 +08001933 int ret;
wanghanlindcacdc42020-12-28 16:19:05 +08001934 f64 timeout = clib_time_now (&wrk->clib_time) + VLS_WORKER_RPC_TIMEOUT;
Florin Coras40c07ce2020-07-16 20:46:17 -07001935
1936 rpc = (vls_rpc_msg_t *) & data;
1937 rpc->type = VLS_RPC_CLONE_AND_SHARE;
1938 msg = (vls_clone_and_share_msg_t *) & rpc->data;
hanlina3a48962020-07-13 11:09:15 +08001939 msg->origin_vls_wrk = vls_wrk_index;
wanghanlindcacdc42020-12-28 16:19:05 +08001940 msg->origin_vls_index = origin_vls_index;
hanlina3a48962020-07-13 11:09:15 +08001941 msg->origin_vcl_wrk = wrk->wrk_index;
1942 msg->origin_session_index = session_index;
Florin Coras40c07ce2020-07-16 20:46:17 -07001943 msg->vls_index = dst_vls_index;
hanlina3a48962020-07-13 11:09:15 +08001944 msg->session_index = dst_session_index;
Florin Coras40c07ce2020-07-16 20:46:17 -07001945
wanghanlindcacdc42020-12-28 16:19:05 +08001946 /* Try lock and handle rpcs if two threads send each other
1947 * clone requests at the same time.
1948 */
1949 wrk->rpc_done = VLS_RPC_STATE_INIT;
1950 while (!clib_spinlock_trylock (&vlsm->worker_rpc_lock))
1951 vcl_flush_mq_events ();
hanlina3a48962020-07-13 11:09:15 +08001952 ret = vcl_send_worker_rpc (dst_wrk_index, rpc, sizeof (data));
1953
Florin Corasff40d8f2020-08-11 22:05:28 -07001954 VDBG (1, "send session clone to wrk (session): %u (%u) -> %u (%u), ret=%d",
hanlina3a48962020-07-13 11:09:15 +08001955 dst_wrk_index, msg->session_index, msg->origin_vcl_wrk,
1956 msg->origin_session_index, ret);
wanghanlindcacdc42020-12-28 16:19:05 +08001957 while (!ret && wrk->rpc_done == VLS_RPC_STATE_INIT &&
1958 clib_time_now (&wrk->clib_time) < timeout)
hanlina3a48962020-07-13 11:09:15 +08001959 ;
wanghanlindcacdc42020-12-28 16:19:05 +08001960 clib_spinlock_unlock (&vlsm->worker_rpc_lock);
hanlina3a48962020-07-13 11:09:15 +08001961}
1962
1963void
1964vls_send_session_cleanup_rpc (vcl_worker_t * wrk,
1965 u32 dst_wrk_index, u32 dst_session_index)
1966{
1967 u8 data[sizeof (u8) + sizeof (vls_sess_cleanup_msg_t)];
1968 vls_sess_cleanup_msg_t *msg;
1969 vls_rpc_msg_t *rpc;
1970 int ret;
1971
1972 rpc = (vls_rpc_msg_t *) & data;
1973 rpc->type = VLS_RPC_SESS_CLEANUP;
1974 msg = (vls_sess_cleanup_msg_t *) & rpc->data;
1975 msg->origin_vcl_wrk = wrk->wrk_index;
1976 msg->session_index = dst_session_index;
1977
hanlina3a48962020-07-13 11:09:15 +08001978 ret = vcl_send_worker_rpc (dst_wrk_index, rpc, sizeof (data));
1979
Florin Corasff40d8f2020-08-11 22:05:28 -07001980 VDBG (1, "send session cleanup to wrk (session): %u (%u) from %u, ret=%d",
hanlina3a48962020-07-13 11:09:15 +08001981 dst_wrk_index, msg->session_index, msg->origin_vcl_wrk, ret);
Florin Coras40c07ce2020-07-16 20:46:17 -07001982}
1983
Florin Coras7baeb712019-01-04 17:05:43 -08001984int
1985vls_app_create (char *app_name)
1986{
1987 int rv;
Florin Coras0ef8ef22019-01-18 08:37:13 -08001988
Florin Coras7baeb712019-01-04 17:05:43 -08001989 if ((rv = vppcom_app_create (app_name)))
1990 return rv;
Florin Coras243edd52020-03-04 22:20:12 +00001991
Florin Coras2d675d72019-01-28 15:54:27 -08001992 vlsm = clib_mem_alloc (sizeof (vls_main_t));
1993 clib_memset (vlsm, 0, sizeof (*vlsm));
Florin Coras243edd52020-03-04 22:20:12 +00001994 clib_rwlock_init (&vlsm->shared_data_lock);
wanghanlindcacdc42020-12-28 16:19:05 +08001995 clib_spinlock_init (&vlsm->worker_rpc_lock);
Florin Coras243edd52020-03-04 22:20:12 +00001996 pool_alloc (vlsm->workers, vcm->cfg.max_workers);
1997
Florin Corasf9240dc2019-01-15 08:03:17 -08001998 pthread_atfork (vls_app_pre_fork, vls_app_fork_parent_handler,
1999 vls_app_fork_child_handler);
Florin Coras0ef8ef22019-01-18 08:37:13 -08002000 atexit (vls_app_exit);
Florin Coras243edd52020-03-04 22:20:12 +00002001 vls_worker_alloc ();
Florin Coras2d675d72019-01-28 15:54:27 -08002002 vlsl->vls_wrk_index = vcl_get_worker_index ();
Florin Corasce4635c2024-10-23 14:19:31 -07002003 vlsl->vls_mt_n_threads = 1;
Florin Coras2e2f9df2021-07-27 22:48:05 -07002004 clib_rwlock_init (&vlsl->vls_pool_lock);
Florin Coras2d675d72019-01-28 15:54:27 -08002005 vls_mt_locks_init ();
Florin Coras40c07ce2020-07-16 20:46:17 -07002006 vcm->wrk_rpc_fn = vls_rpc_handler;
Florin Corasce4635c2024-10-23 14:19:31 -07002007
Florin Coras7baeb712019-01-04 17:05:43 -08002008 return VPPCOM_OK;
2009}
2010
hanlin4266d4d2020-05-19 17:34:17 +08002011unsigned char
2012vls_use_eventfd (void)
2013{
2014 return vcm->cfg.use_mq_eventfd;
2015}
2016
hanlina3a48962020-07-13 11:09:15 +08002017unsigned char
2018vls_mt_wrk_supported (void)
2019{
Florin Corasff40d8f2020-08-11 22:05:28 -07002020 return vcm->cfg.mt_wrk_supported;
hanlina3a48962020-07-13 11:09:15 +08002021}
2022
2023int
2024vls_use_real_epoll (void)
2025{
2026 if (vcl_get_worker_index () == ~0)
2027 return 0;
2028
2029 return vcl_worker_get_current ()->vcl_needs_real_epoll;
2030}
2031
Florin Coras978d48b2024-11-26 00:29:24 -08002032int
2033vls_set_libc_epfd (vls_handle_t ep_vlsh, int libc_epfd)
2034{
2035 vcl_locked_session_t *vls;
2036
2037 vls_mt_detect ();
2038 if (!(vls = vls_get_w_dlock (ep_vlsh)))
2039 return VPPCOM_EBADFD;
2040 if (vls_mt_session_should_migrate (vls))
2041 {
2042 vls = vls_mt_session_migrate (vls);
2043 if (PREDICT_FALSE (!vls))
2044 return VPPCOM_EBADFD;
2045 }
2046 vls->libc_epfd = libc_epfd;
2047 vls_unlock (vls);
2048 vls_mt_pool_runlock ();
2049 return 0;
2050}
2051
2052int
2053vls_get_libc_epfd (vls_handle_t ep_vlsh)
2054{
2055 vcl_locked_session_t *vls;
2056 int rv;
2057
2058 vls_mt_detect ();
2059 vls_mt_pool_rlock ();
2060
2061 vls = vls_get (ep_vlsh);
2062 if (!vls)
2063 {
2064 vls_mt_pool_runlock ();
2065 return VPPCOM_EBADFD;
2066 }
2067
2068 /* Avoid locking. In mt scenarios, one thread might be blocking waiting on
2069 * the fd while another might be closing it. While closing, this attribute
2070 * might be retrieved, so avoid deadlock */
2071 rv = vls->libc_epfd;
2072
2073 vls_mt_pool_runlock ();
2074
2075 return rv;
2076}
2077
hanlina3a48962020-07-13 11:09:15 +08002078void
2079vls_register_vcl_worker (void)
2080{
wanghanlin492350e2020-09-11 17:19:32 +08002081 vls_mt_add ();
hanlina3a48962020-07-13 11:09:15 +08002082}
2083
Florin Coras7baeb712019-01-04 17:05:43 -08002084/*
2085 * fd.io coding-style-patch-verification: ON
2086 *
2087 * Local Variables:
2088 * eval: (c-set-style "gnu")
2089 * End:
2090 */