Florin Coras | 7baeb71 | 2019-01-04 17:05:43 -0800 | [diff] [blame^] | 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 | */ |