blob: 6254bad09b610e7796745d90010223d0b9320091 [file] [log] [blame]
/*
* 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:
*/