summaryrefslogtreecommitdiffstats
path: root/src/vcl/vcl_locked.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vcl/vcl_locked.c')
-rw-r--r--src/vcl/vcl_locked.c457
1 files changed, 457 insertions, 0 deletions
diff --git a/src/vcl/vcl_locked.c b/src/vcl/vcl_locked.c
new file mode 100644
index 00000000000..6254bad09b6
--- /dev/null
+++ b/src/vcl/vcl_locked.c
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vcl/vcl_locked.h>
+#include <vcl/vcl_private.h>
+
+typedef struct vcl_locked_session_
+{
+ u32 session_index;
+ u32 worker_index;
+ u32 vls_index;
+ u32 flags;
+ clib_spinlock_t lock;
+} vcl_locked_session_t;
+
+typedef struct vcl_main_
+{
+ vcl_locked_session_t *vls_pool;
+ clib_rwlock_t vls_table_lock;
+ uword *session_index_to_vlsh_table;
+} vls_main_t;
+
+vls_main_t vls_main;
+vls_main_t *vlsm = &vls_main;
+
+static inline void
+vls_table_rlock (void)
+{
+ clib_rwlock_reader_lock (&vlsm->vls_table_lock);
+}
+
+static inline void
+vls_table_runlock (void)
+{
+ clib_rwlock_reader_unlock (&vlsm->vls_table_lock);
+}
+
+static inline void
+vls_table_wlock (void)
+{
+ clib_rwlock_writer_lock (&vlsm->vls_table_lock);
+}
+
+static inline void
+vls_table_wunlock (void)
+{
+ clib_rwlock_writer_unlock (&vlsm->vls_table_lock);
+}
+
+static inline vcl_session_handle_t
+vls_to_sh (vcl_locked_session_t * vls)
+{
+ return vppcom_session_handle (vls->session_index);
+}
+
+static inline vcl_session_handle_t
+vls_to_sh_tu (vcl_locked_session_t * vls)
+{
+ vcl_session_handle_t sh;
+ sh = vls_to_sh (vls);
+ vls_table_runlock ();
+ return sh;
+}
+
+static vls_handle_t
+vls_alloc (vcl_session_handle_t sh)
+{
+ vcl_locked_session_t *vls;
+
+ vls_table_wlock ();
+ pool_get (vlsm->vls_pool, vls);
+ vls->session_index = vppcom_session_index (sh);
+ vls->worker_index = vppcom_session_worker (sh);
+ vls->vls_index = vls - vlsm->vls_pool;
+ hash_set (vlsm->session_index_to_vlsh_table, vls->session_index,
+ vls->vls_index);
+ clib_spinlock_init (&vls->lock);
+ vls_table_wunlock ();
+ return vls->vls_index;
+}
+
+static vcl_locked_session_t *
+vls_get (vls_handle_t vlsh)
+{
+ if (pool_is_free_index (vlsm->vls_pool, vlsh))
+ return 0;
+ return pool_elt_at_index (vlsm->vls_pool, vlsh);
+}
+
+static void
+vls_free (vcl_locked_session_t * fde)
+{
+ ASSERT (fde != 0);
+ hash_unset (vlsm->session_index_to_vlsh_table, fde->session_index);
+ clib_spinlock_free (&fde->lock);
+ pool_put (vlsm->vls_pool, fde);
+}
+
+static vcl_locked_session_t *
+vls_get_and_lock (vls_handle_t vlsh)
+{
+ vcl_locked_session_t *vls;
+ if (pool_is_free_index (vlsm->vls_pool, vlsh))
+ return 0;
+ vls = pool_elt_at_index (vlsm->vls_pool, vlsh);
+ clib_spinlock_lock (&vls->lock);
+ return vls;
+}
+
+static vcl_locked_session_t *
+vls_get_w_dlock (vls_handle_t vlsh)
+{
+ vcl_locked_session_t *vls;
+ vls_table_rlock ();
+ vls = vls_get_and_lock (vlsh);
+ if (!vls)
+ vls_table_runlock ();
+ return vls;
+}
+
+static inline void
+vls_unlock (vcl_locked_session_t * vls)
+{
+ clib_spinlock_unlock (&vls->lock);
+}
+
+static inline void
+vls_get_and_unlock (vls_handle_t vlsh)
+{
+ vcl_locked_session_t *vls;
+ vls_table_rlock ();
+ vls = vls_get (vlsh);
+ vls_unlock (vls);
+ vls_table_runlock ();
+}
+
+static inline void
+vls_dunlock (vcl_locked_session_t * vls)
+{
+ vls_unlock (vls);
+ vls_table_runlock ();
+}
+
+static void
+vls_get_and_free (vls_handle_t vlsh)
+{
+ vcl_locked_session_t *vls;
+
+ vls_table_wlock ();
+ vls = vls_get (vlsh);
+ vls_free (vls);
+ vls_table_wunlock ();
+}
+
+int
+vls_write (vls_handle_t vlsh, void *buf, size_t nbytes)
+{
+ vcl_locked_session_t *vls;
+ int rv;
+
+ if (!(vls = vls_get_w_dlock (vlsh)))
+ return VPPCOM_EBADFD;
+ rv = vppcom_session_write (vls_to_sh_tu (vls), buf, nbytes);
+ vls_get_and_unlock (vlsh);
+ return rv;
+}
+
+int
+vls_write_msg (vls_handle_t vlsh, void *buf, size_t nbytes)
+{
+ vcl_locked_session_t *vls;
+ int rv;
+
+ if (!(vls = vls_get_w_dlock (vlsh)))
+ return VPPCOM_EBADFD;
+ rv = vppcom_session_write_msg (vls_to_sh_tu (vls), buf, nbytes);
+ vls_get_and_unlock (vlsh);
+ return rv;
+}
+
+int
+vls_sendto (vls_handle_t vlsh, void *buf, int buflen, int flags,
+ vppcom_endpt_t * ep)
+{
+ vcl_locked_session_t *vls;
+ int rv;
+
+ if (!(vls = vls_get_w_dlock (vlsh)))
+ return VPPCOM_EBADFD;
+ rv = vppcom_session_sendto (vls_to_sh_tu (vls), buf, buflen, flags, ep);
+ vls_get_and_unlock (vlsh);
+ return rv;
+}
+
+ssize_t
+vls_read (vls_handle_t vlsh, void *buf, size_t nbytes)
+{
+ vcl_locked_session_t *vls;
+ int rv;
+
+ if (!(vls = vls_get_w_dlock (vlsh)))
+ return VPPCOM_EBADFD;
+ rv = vppcom_session_read (vls_to_sh_tu (vls), buf, nbytes);
+ vls_get_and_unlock (vlsh);
+ return rv;
+}
+
+ssize_t
+vls_recvfrom (vls_handle_t vlsh, void *buffer, uint32_t buflen, int flags,
+ vppcom_endpt_t * ep)
+{
+ vcl_locked_session_t *vls;
+ int rv;
+
+ if (!(vls = vls_get_w_dlock (vlsh)))
+ return VPPCOM_EBADFD;
+ rv = vppcom_session_recvfrom (vls_to_sh_tu (vls), buffer, buflen, flags,
+ ep);
+ vls_get_and_unlock (vlsh);
+ return rv;
+}
+
+int
+vls_attr (vls_handle_t vlsh, uint32_t op, void *buffer, uint32_t * buflen)
+{
+ vcl_locked_session_t *vls;
+ int rv;
+
+ if (!(vls = vls_get_w_dlock (vlsh)))
+ return VPPCOM_EBADFD;
+ rv = vppcom_session_attr (vls_to_sh_tu (vls), op, buffer, buflen);
+ vls_get_and_unlock (vlsh);
+ return rv;
+}
+
+int
+vls_bind (vls_handle_t vlsh, vppcom_endpt_t * ep)
+{
+ vcl_locked_session_t *vls;
+ int rv;
+
+ if (!(vls = vls_get_w_dlock (vlsh)))
+ return VPPCOM_EBADFD;
+ rv = vppcom_session_bind (vls_to_sh_tu (vls), ep);
+ vls_get_and_unlock (vlsh);
+ return rv;
+}
+
+int
+vls_listen (vls_handle_t vlsh, int q_len)
+{
+ vcl_locked_session_t *vls;
+ int rv;
+
+ if (!(vls = vls_get_w_dlock (vlsh)))
+ return VPPCOM_EBADFD;
+ rv = vppcom_session_listen (vls_to_sh_tu (vls), q_len);
+ vls_get_and_unlock (vlsh);
+ return rv;
+}
+
+int
+vls_connect (vls_handle_t vlsh, vppcom_endpt_t * server_ep)
+{
+ vcl_locked_session_t *vls;
+ int rv;
+
+ if (!(vls = vls_get_w_dlock (vlsh)))
+ return VPPCOM_EBADFD;
+ rv = vppcom_session_connect (vls_to_sh_tu (vls), server_ep);
+ vls_get_and_unlock (vlsh);
+ return rv;
+}
+
+vls_handle_t
+vls_accept (vls_handle_t listener_vlsh, vppcom_endpt_t * ep, int flags)
+{
+ vls_handle_t accepted_vlsh;
+ vcl_locked_session_t *vls;
+ int sh;
+
+ if (!(vls = vls_get_w_dlock (listener_vlsh)))
+ return VPPCOM_EBADFD;
+ sh = vppcom_session_accept (vls_to_sh_tu (vls), ep, flags);
+ vls_get_and_unlock (listener_vlsh);
+ if (sh < 0)
+ return sh;
+ accepted_vlsh = vls_alloc (sh);
+ if (PREDICT_FALSE (accepted_vlsh == VLS_INVALID_HANDLE))
+ vppcom_session_close (sh);
+ return accepted_vlsh;
+}
+
+vls_handle_t
+vls_create (uint8_t proto, uint8_t is_nonblocking)
+{
+ vcl_session_handle_t sh;
+ vls_handle_t vlsh;
+
+ sh = vppcom_session_create (proto, is_nonblocking);
+ if (sh == INVALID_SESSION_ID)
+ return VLS_INVALID_HANDLE;
+
+ vlsh = vls_alloc (sh);
+ if (PREDICT_FALSE (vlsh == VLS_INVALID_HANDLE))
+ vppcom_session_close (sh);
+
+ return vlsh;
+}
+
+int
+vls_close (vls_handle_t vlsh)
+{
+ vcl_locked_session_t *vls;
+ vcl_session_handle_t sh;
+ int rv, refcnt;
+
+ if (!(vls = vls_get_w_dlock (vlsh)))
+ return VPPCOM_EBADFD;
+
+ sh = vls_to_sh (vls);
+ refcnt = vppcom_session_attr (sh, VPPCOM_ATTR_GET_REFCNT, 0, 0);
+ if ((rv = vppcom_session_close (sh)))
+ {
+ vls_dunlock (vls);
+ return rv;
+ }
+
+ vls_dunlock (vls);
+ if (refcnt <= 1)
+ vls_get_and_free (vlsh);
+ return rv;
+}
+
+vls_handle_t
+vls_epoll_create (void)
+{
+ vcl_session_handle_t sh;
+ vls_handle_t vlsh;
+
+ sh = vppcom_epoll_create ();
+ if (sh == INVALID_SESSION_ID)
+ return VLS_INVALID_HANDLE;
+
+ vlsh = vls_alloc (sh);
+ if (vlsh == VLS_INVALID_HANDLE)
+ vppcom_session_close (sh);
+
+ return vlsh;
+}
+
+int
+vls_epoll_ctl (vls_handle_t ep_vlsh, int op, vls_handle_t vlsh,
+ struct epoll_event *event)
+{
+ vcl_locked_session_t *ep_vls, *vls;
+ vcl_session_handle_t ep_sh, sh;
+ int rv;
+
+ vls_table_rlock ();
+ ep_vls = vls_get_and_lock (ep_vlsh);
+ vls = vls_get_and_lock (vlsh);
+ ep_sh = vls_to_sh (ep_vls);
+ sh = vls_to_sh (vls);
+ vls_table_runlock ();
+
+ rv = vppcom_epoll_ctl (ep_sh, op, sh, event);
+
+ vls_table_rlock ();
+ ep_vls = vls_get (ep_vlsh);
+ vls = vls_get (vlsh);
+ vls_unlock (vls);
+ vls_unlock (ep_vls);
+ vls_table_runlock ();
+ return rv;
+}
+
+int
+vls_epoll_wait (vls_handle_t ep_vlsh, struct epoll_event *events,
+ int maxevents, double wait_for_time)
+{
+ vcl_locked_session_t *vls;
+ int rv;
+
+ if (!(vls = vls_get_w_dlock (ep_vlsh)))
+ return VPPCOM_EBADFD;
+ rv = vppcom_epoll_wait (vls_to_sh_tu (vls), events, maxevents,
+ wait_for_time);
+ vls_get_and_unlock (ep_vlsh);
+ return rv;
+}
+
+vcl_session_handle_t
+vlsh_to_sh (vls_handle_t vlsh)
+{
+ vcl_locked_session_t *vls;
+ int rv;
+
+ vls = vls_get_w_dlock (vlsh);
+ if (!vls)
+ return INVALID_SESSION_ID;
+ rv = vls_to_sh (vls);
+ vls_dunlock (vls);
+ return rv;
+}
+
+vcl_session_handle_t
+vlsh_to_session_index (vls_handle_t vlsh)
+{
+ vcl_session_handle_t sh;
+ sh = vlsh_to_sh (vlsh);
+ return vppcom_session_index (sh);
+}
+
+vls_handle_t
+vls_session_index_to_vlsh (uint32_t session_index)
+{
+ vls_handle_t vlsh;
+ uword *vlshp;
+
+ vls_table_rlock ();
+ vlshp = hash_get (vlsm->session_index_to_vlsh_table, session_index);
+ vlsh = vlshp ? *vlshp : VLS_INVALID_HANDLE;
+ vls_table_runlock ();
+
+ return vlsh;
+}
+
+int
+vls_app_create (char *app_name)
+{
+ int rv;
+ if ((rv = vppcom_app_create (app_name)))
+ return rv;
+ clib_rwlock_init (&vlsm->vls_table_lock);
+ return VPPCOM_OK;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */