vcl/ldp: add locked sessions shim layer
[vpp.git] / src / vcl / vcl_locked.c
1 /*
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
19 typedef struct vcl_locked_session_
20 {
21   u32 session_index;
22   u32 worker_index;
23   u32 vls_index;
24   u32 flags;
25   clib_spinlock_t lock;
26 } vcl_locked_session_t;
27
28 typedef struct vcl_main_
29 {
30   vcl_locked_session_t *vls_pool;
31   clib_rwlock_t vls_table_lock;
32   uword *session_index_to_vlsh_table;
33 } vls_main_t;
34
35 vls_main_t vls_main;
36 vls_main_t *vlsm = &vls_main;
37
38 static inline void
39 vls_table_rlock (void)
40 {
41   clib_rwlock_reader_lock (&vlsm->vls_table_lock);
42 }
43
44 static inline void
45 vls_table_runlock (void)
46 {
47   clib_rwlock_reader_unlock (&vlsm->vls_table_lock);
48 }
49
50 static inline void
51 vls_table_wlock (void)
52 {
53   clib_rwlock_writer_lock (&vlsm->vls_table_lock);
54 }
55
56 static inline void
57 vls_table_wunlock (void)
58 {
59   clib_rwlock_writer_unlock (&vlsm->vls_table_lock);
60 }
61
62 static inline vcl_session_handle_t
63 vls_to_sh (vcl_locked_session_t * vls)
64 {
65   return vppcom_session_handle (vls->session_index);
66 }
67
68 static inline vcl_session_handle_t
69 vls_to_sh_tu (vcl_locked_session_t * vls)
70 {
71   vcl_session_handle_t sh;
72   sh = vls_to_sh (vls);
73   vls_table_runlock ();
74   return sh;
75 }
76
77 static vls_handle_t
78 vls_alloc (vcl_session_handle_t sh)
79 {
80   vcl_locked_session_t *vls;
81
82   vls_table_wlock ();
83   pool_get (vlsm->vls_pool, vls);
84   vls->session_index = vppcom_session_index (sh);
85   vls->worker_index = vppcom_session_worker (sh);
86   vls->vls_index = vls - vlsm->vls_pool;
87   hash_set (vlsm->session_index_to_vlsh_table, vls->session_index,
88             vls->vls_index);
89   clib_spinlock_init (&vls->lock);
90   vls_table_wunlock ();
91   return vls->vls_index;
92 }
93
94 static vcl_locked_session_t *
95 vls_get (vls_handle_t vlsh)
96 {
97   if (pool_is_free_index (vlsm->vls_pool, vlsh))
98     return 0;
99   return pool_elt_at_index (vlsm->vls_pool, vlsh);
100 }
101
102 static void
103 vls_free (vcl_locked_session_t * fde)
104 {
105   ASSERT (fde != 0);
106   hash_unset (vlsm->session_index_to_vlsh_table, fde->session_index);
107   clib_spinlock_free (&fde->lock);
108   pool_put (vlsm->vls_pool, fde);
109 }
110
111 static vcl_locked_session_t *
112 vls_get_and_lock (vls_handle_t vlsh)
113 {
114   vcl_locked_session_t *vls;
115   if (pool_is_free_index (vlsm->vls_pool, vlsh))
116     return 0;
117   vls = pool_elt_at_index (vlsm->vls_pool, vlsh);
118   clib_spinlock_lock (&vls->lock);
119   return vls;
120 }
121
122 static vcl_locked_session_t *
123 vls_get_w_dlock (vls_handle_t vlsh)
124 {
125   vcl_locked_session_t *vls;
126   vls_table_rlock ();
127   vls = vls_get_and_lock (vlsh);
128   if (!vls)
129     vls_table_runlock ();
130   return vls;
131 }
132
133 static inline void
134 vls_unlock (vcl_locked_session_t * vls)
135 {
136   clib_spinlock_unlock (&vls->lock);
137 }
138
139 static inline void
140 vls_get_and_unlock (vls_handle_t vlsh)
141 {
142   vcl_locked_session_t *vls;
143   vls_table_rlock ();
144   vls = vls_get (vlsh);
145   vls_unlock (vls);
146   vls_table_runlock ();
147 }
148
149 static inline void
150 vls_dunlock (vcl_locked_session_t * vls)
151 {
152   vls_unlock (vls);
153   vls_table_runlock ();
154 }
155
156 static void
157 vls_get_and_free (vls_handle_t vlsh)
158 {
159   vcl_locked_session_t *vls;
160
161   vls_table_wlock ();
162   vls = vls_get (vlsh);
163   vls_free (vls);
164   vls_table_wunlock ();
165 }
166
167 int
168 vls_write (vls_handle_t vlsh, void *buf, size_t nbytes)
169 {
170   vcl_locked_session_t *vls;
171   int rv;
172
173   if (!(vls = vls_get_w_dlock (vlsh)))
174     return VPPCOM_EBADFD;
175   rv = vppcom_session_write (vls_to_sh_tu (vls), buf, nbytes);
176   vls_get_and_unlock (vlsh);
177   return rv;
178 }
179
180 int
181 vls_write_msg (vls_handle_t vlsh, void *buf, size_t nbytes)
182 {
183   vcl_locked_session_t *vls;
184   int rv;
185
186   if (!(vls = vls_get_w_dlock (vlsh)))
187     return VPPCOM_EBADFD;
188   rv = vppcom_session_write_msg (vls_to_sh_tu (vls), buf, nbytes);
189   vls_get_and_unlock (vlsh);
190   return rv;
191 }
192
193 int
194 vls_sendto (vls_handle_t vlsh, void *buf, int buflen, int flags,
195             vppcom_endpt_t * ep)
196 {
197   vcl_locked_session_t *vls;
198   int rv;
199
200   if (!(vls = vls_get_w_dlock (vlsh)))
201     return VPPCOM_EBADFD;
202   rv = vppcom_session_sendto (vls_to_sh_tu (vls), buf, buflen, flags, ep);
203   vls_get_and_unlock (vlsh);
204   return rv;
205 }
206
207 ssize_t
208 vls_read (vls_handle_t vlsh, void *buf, size_t nbytes)
209 {
210   vcl_locked_session_t *vls;
211   int rv;
212
213   if (!(vls = vls_get_w_dlock (vlsh)))
214     return VPPCOM_EBADFD;
215   rv = vppcom_session_read (vls_to_sh_tu (vls), buf, nbytes);
216   vls_get_and_unlock (vlsh);
217   return rv;
218 }
219
220 ssize_t
221 vls_recvfrom (vls_handle_t vlsh, void *buffer, uint32_t buflen, int flags,
222               vppcom_endpt_t * ep)
223 {
224   vcl_locked_session_t *vls;
225   int rv;
226
227   if (!(vls = vls_get_w_dlock (vlsh)))
228     return VPPCOM_EBADFD;
229   rv = vppcom_session_recvfrom (vls_to_sh_tu (vls), buffer, buflen, flags,
230                                 ep);
231   vls_get_and_unlock (vlsh);
232   return rv;
233 }
234
235 int
236 vls_attr (vls_handle_t vlsh, uint32_t op, void *buffer, uint32_t * buflen)
237 {
238   vcl_locked_session_t *vls;
239   int rv;
240
241   if (!(vls = vls_get_w_dlock (vlsh)))
242     return VPPCOM_EBADFD;
243   rv = vppcom_session_attr (vls_to_sh_tu (vls), op, buffer, buflen);
244   vls_get_and_unlock (vlsh);
245   return rv;
246 }
247
248 int
249 vls_bind (vls_handle_t vlsh, vppcom_endpt_t * ep)
250 {
251   vcl_locked_session_t *vls;
252   int rv;
253
254   if (!(vls = vls_get_w_dlock (vlsh)))
255     return VPPCOM_EBADFD;
256   rv = vppcom_session_bind (vls_to_sh_tu (vls), ep);
257   vls_get_and_unlock (vlsh);
258   return rv;
259 }
260
261 int
262 vls_listen (vls_handle_t vlsh, int q_len)
263 {
264   vcl_locked_session_t *vls;
265   int rv;
266
267   if (!(vls = vls_get_w_dlock (vlsh)))
268     return VPPCOM_EBADFD;
269   rv = vppcom_session_listen (vls_to_sh_tu (vls), q_len);
270   vls_get_and_unlock (vlsh);
271   return rv;
272 }
273
274 int
275 vls_connect (vls_handle_t vlsh, vppcom_endpt_t * server_ep)
276 {
277   vcl_locked_session_t *vls;
278   int rv;
279
280   if (!(vls = vls_get_w_dlock (vlsh)))
281     return VPPCOM_EBADFD;
282   rv = vppcom_session_connect (vls_to_sh_tu (vls), server_ep);
283   vls_get_and_unlock (vlsh);
284   return rv;
285 }
286
287 vls_handle_t
288 vls_accept (vls_handle_t listener_vlsh, vppcom_endpt_t * ep, int flags)
289 {
290   vls_handle_t accepted_vlsh;
291   vcl_locked_session_t *vls;
292   int sh;
293
294   if (!(vls = vls_get_w_dlock (listener_vlsh)))
295     return VPPCOM_EBADFD;
296   sh = vppcom_session_accept (vls_to_sh_tu (vls), ep, flags);
297   vls_get_and_unlock (listener_vlsh);
298   if (sh < 0)
299     return sh;
300   accepted_vlsh = vls_alloc (sh);
301   if (PREDICT_FALSE (accepted_vlsh == VLS_INVALID_HANDLE))
302     vppcom_session_close (sh);
303   return accepted_vlsh;
304 }
305
306 vls_handle_t
307 vls_create (uint8_t proto, uint8_t is_nonblocking)
308 {
309   vcl_session_handle_t sh;
310   vls_handle_t vlsh;
311
312   sh = vppcom_session_create (proto, is_nonblocking);
313   if (sh == INVALID_SESSION_ID)
314     return VLS_INVALID_HANDLE;
315
316   vlsh = vls_alloc (sh);
317   if (PREDICT_FALSE (vlsh == VLS_INVALID_HANDLE))
318     vppcom_session_close (sh);
319
320   return vlsh;
321 }
322
323 int
324 vls_close (vls_handle_t vlsh)
325 {
326   vcl_locked_session_t *vls;
327   vcl_session_handle_t sh;
328   int rv, refcnt;
329
330   if (!(vls = vls_get_w_dlock (vlsh)))
331     return VPPCOM_EBADFD;
332
333   sh = vls_to_sh (vls);
334   refcnt = vppcom_session_attr (sh, VPPCOM_ATTR_GET_REFCNT, 0, 0);
335   if ((rv = vppcom_session_close (sh)))
336     {
337       vls_dunlock (vls);
338       return rv;
339     }
340
341   vls_dunlock (vls);
342   if (refcnt <= 1)
343     vls_get_and_free (vlsh);
344   return rv;
345 }
346
347 vls_handle_t
348 vls_epoll_create (void)
349 {
350   vcl_session_handle_t sh;
351   vls_handle_t vlsh;
352
353   sh = vppcom_epoll_create ();
354   if (sh == INVALID_SESSION_ID)
355     return VLS_INVALID_HANDLE;
356
357   vlsh = vls_alloc (sh);
358   if (vlsh == VLS_INVALID_HANDLE)
359     vppcom_session_close (sh);
360
361   return vlsh;
362 }
363
364 int
365 vls_epoll_ctl (vls_handle_t ep_vlsh, int op, vls_handle_t vlsh,
366                struct epoll_event *event)
367 {
368   vcl_locked_session_t *ep_vls, *vls;
369   vcl_session_handle_t ep_sh, sh;
370   int rv;
371
372   vls_table_rlock ();
373   ep_vls = vls_get_and_lock (ep_vlsh);
374   vls = vls_get_and_lock (vlsh);
375   ep_sh = vls_to_sh (ep_vls);
376   sh = vls_to_sh (vls);
377   vls_table_runlock ();
378
379   rv = vppcom_epoll_ctl (ep_sh, op, sh, event);
380
381   vls_table_rlock ();
382   ep_vls = vls_get (ep_vlsh);
383   vls = vls_get (vlsh);
384   vls_unlock (vls);
385   vls_unlock (ep_vls);
386   vls_table_runlock ();
387   return rv;
388 }
389
390 int
391 vls_epoll_wait (vls_handle_t ep_vlsh, struct epoll_event *events,
392                 int maxevents, double wait_for_time)
393 {
394   vcl_locked_session_t *vls;
395   int rv;
396
397   if (!(vls = vls_get_w_dlock (ep_vlsh)))
398     return VPPCOM_EBADFD;
399   rv = vppcom_epoll_wait (vls_to_sh_tu (vls), events, maxevents,
400                           wait_for_time);
401   vls_get_and_unlock (ep_vlsh);
402   return rv;
403 }
404
405 vcl_session_handle_t
406 vlsh_to_sh (vls_handle_t vlsh)
407 {
408   vcl_locked_session_t *vls;
409   int rv;
410
411   vls = vls_get_w_dlock (vlsh);
412   if (!vls)
413     return INVALID_SESSION_ID;
414   rv = vls_to_sh (vls);
415   vls_dunlock (vls);
416   return rv;
417 }
418
419 vcl_session_handle_t
420 vlsh_to_session_index (vls_handle_t vlsh)
421 {
422   vcl_session_handle_t sh;
423   sh = vlsh_to_sh (vlsh);
424   return vppcom_session_index (sh);
425 }
426
427 vls_handle_t
428 vls_session_index_to_vlsh (uint32_t session_index)
429 {
430   vls_handle_t vlsh;
431   uword *vlshp;
432
433   vls_table_rlock ();
434   vlshp = hash_get (vlsm->session_index_to_vlsh_table, session_index);
435   vlsh = vlshp ? *vlshp : VLS_INVALID_HANDLE;
436   vls_table_runlock ();
437
438   return vlsh;
439 }
440
441 int
442 vls_app_create (char *app_name)
443 {
444   int rv;
445   if ((rv = vppcom_app_create (app_name)))
446     return rv;
447   clib_rwlock_init (&vlsm->vls_table_lock);
448   return VPPCOM_OK;
449 }
450
451 /*
452  * fd.io coding-style-patch-verification: ON
453  *
454  * Local Variables:
455  * eval: (c-set-style "gnu")
456  * End:
457  */