#include <stdlib.h>
#include <errno.h>
#include <umem.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/avl.h>
#include <stddef.h>
#include <stdio.h>
#include <strings.h>
#include <libvarpd_impl.h>
static int
libvarpd_instance_comparator(const void *lp, const void *rp)
{
const varpd_instance_t *lpp, *rpp;
lpp = lp;
rpp = rp;
if (lpp->vri_id > rpp->vri_id)
return (1);
if (lpp->vri_id < rpp->vri_id)
return (-1);
return (0);
}
static int
libvarpd_instance_lcomparator(const void *lp, const void *rp)
{
const varpd_instance_t *lpp, *rpp;
lpp = lp;
rpp = rp;
if (lpp->vri_linkid > rpp->vri_linkid)
return (1);
if (lpp->vri_linkid < rpp->vri_linkid)
return (-1);
return (0);
}
int
libvarpd_create(varpd_handle_t **vphp)
{
int ret;
varpd_impl_t *vip;
char buf[32];
if (vphp == NULL)
return (EINVAL);
*vphp = NULL;
vip = umem_alloc(sizeof (varpd_impl_t), UMEM_DEFAULT);
if (vip == NULL)
return (errno);
bzero(vip, sizeof (varpd_impl_t));
(void) snprintf(buf, sizeof (buf), "varpd_%p", vip);
vip->vdi_idspace = id_space_create(buf, LIBVARPD_ID_MIN,
LIBVARPD_ID_MAX);
if (vip->vdi_idspace == NULL) {
int ret = errno;
umem_free(vip, sizeof (varpd_impl_t));
return (ret);
}
vip->vdi_qcache = umem_cache_create("query", sizeof (varpd_query_t), 0,
NULL, NULL, NULL, NULL, NULL, 0);
if (vip->vdi_qcache == NULL) {
int ret = errno;
id_space_destroy(vip->vdi_idspace);
umem_free(vip, sizeof (varpd_impl_t));
return (ret);
}
if ((ret = libvarpd_overlay_init(vip)) != 0) {
umem_cache_destroy(vip->vdi_qcache);
id_space_destroy(vip->vdi_idspace);
umem_free(vip, sizeof (varpd_impl_t));
return (ret);
}
libvarpd_persist_init(vip);
avl_create(&vip->vdi_plugins, libvarpd_plugin_comparator,
sizeof (varpd_plugin_t), offsetof(varpd_plugin_t, vpp_node));
avl_create(&vip->vdi_instances, libvarpd_instance_comparator,
sizeof (varpd_instance_t), offsetof(varpd_instance_t, vri_inode));
avl_create(&vip->vdi_linstances, libvarpd_instance_lcomparator,
sizeof (varpd_instance_t), offsetof(varpd_instance_t, vri_lnode));
if (mutex_init(&vip->vdi_lock, USYNC_THREAD | LOCK_ERRORCHECK,
NULL) != 0)
libvarpd_panic("failed to create mutex: %d", errno);
vip->vdi_doorfd = -1;
*vphp = (varpd_handle_t *)vip;
return (0);
}
void
libvarpd_destroy(varpd_handle_t *vhp)
{
varpd_impl_t *vip = (varpd_impl_t *)vhp;
libvarpd_overlay_lookup_quiesce(vhp);
if (mutex_destroy(&vip->vdi_lock) != 0)
libvarpd_panic("failed to destroy mutex: %d", errno);
libvarpd_persist_fini(vip);
libvarpd_overlay_fini(vip);
umem_cache_destroy(vip->vdi_qcache);
id_space_destroy(vip->vdi_idspace);
umem_free(vip, sizeof (varpd_impl_t));
}
int
libvarpd_instance_create(varpd_handle_t *vhp, datalink_id_t linkid,
const char *pname, varpd_instance_handle_t **outp)
{
int ret;
varpd_impl_t *vip = (varpd_impl_t *)vhp;
varpd_plugin_t *plugin;
varpd_instance_t *inst, lookup;
overlay_plugin_dest_t dest;
uint64_t vid;
plugin = libvarpd_plugin_lookup(vip, pname);
if (plugin == NULL)
return (ENOENT);
if ((ret = libvarpd_overlay_info(vip, linkid, &dest, NULL, &vid)) != 0)
return (ret);
inst = umem_alloc(sizeof (varpd_instance_t), UMEM_DEFAULT);
if (inst == NULL)
return (ENOMEM);
inst->vri_id = id_alloc(vip->vdi_idspace);
if (inst->vri_id == -1)
libvarpd_panic("failed to allocate id from vdi_idspace: %d",
errno);
inst->vri_linkid = linkid;
inst->vri_vnetid = vid;
inst->vri_mode = plugin->vpp_mode;
inst->vri_dest = dest;
inst->vri_plugin = plugin;
inst->vri_impl = vip;
inst->vri_flags = 0;
if ((ret = plugin->vpp_ops->vpo_create((varpd_provider_handle_t *)inst,
&inst->vri_private, dest)) != 0) {
id_free(vip->vdi_idspace, inst->vri_id);
umem_free(inst, sizeof (varpd_instance_t));
return (ret);
}
if (mutex_init(&inst->vri_lock, USYNC_THREAD | LOCK_ERRORCHECK,
NULL) != 0)
libvarpd_panic("failed to create mutex: %d", errno);
mutex_enter(&vip->vdi_lock);
lookup.vri_id = inst->vri_id;
if (avl_find(&vip->vdi_instances, &lookup, NULL) != NULL)
libvarpd_panic("found duplicate instance with id %d",
lookup.vri_id);
avl_add(&vip->vdi_instances, inst);
lookup.vri_linkid = inst->vri_linkid;
if (avl_find(&vip->vdi_linstances, &lookup, NULL) != NULL)
libvarpd_panic("found duplicate linstance with id %d",
lookup.vri_linkid);
avl_add(&vip->vdi_linstances, inst);
mutex_exit(&vip->vdi_lock);
*outp = (varpd_instance_handle_t *)inst;
return (0);
}
uint64_t
libvarpd_instance_id(varpd_instance_handle_t *ihp)
{
varpd_instance_t *inst = (varpd_instance_t *)ihp;
return (inst->vri_id);
}
uint64_t
libvarpd_plugin_vnetid(varpd_provider_handle_t *vhp)
{
varpd_instance_t *inst = (varpd_instance_t *)vhp;
return (inst->vri_vnetid);
}
varpd_instance_handle_t *
libvarpd_instance_lookup(varpd_handle_t *vhp, uint64_t id)
{
varpd_impl_t *vip = (varpd_impl_t *)vhp;
varpd_instance_t lookup, *retp;
lookup.vri_id = id;
mutex_enter(&vip->vdi_lock);
retp = avl_find(&vip->vdi_instances, &lookup, NULL);
mutex_exit(&vip->vdi_lock);
return ((varpd_instance_handle_t *)retp);
}
varpd_instance_t *
libvarpd_instance_lookup_by_dlid(varpd_impl_t *vip, datalink_id_t linkid)
{
varpd_instance_t lookup, *retp;
lookup.vri_linkid = linkid;
mutex_enter(&vip->vdi_lock);
retp = avl_find(&vip->vdi_linstances, &lookup, NULL);
mutex_exit(&vip->vdi_lock);
return (retp);
}
void
libvarpd_instance_destroy(varpd_instance_handle_t *ihp)
{
varpd_instance_t *inst = (varpd_instance_t *)ihp;
varpd_impl_t *vip = inst->vri_impl;
mutex_enter(&vip->vdi_lock);
avl_remove(&vip->vdi_instances, inst);
avl_remove(&vip->vdi_linstances, inst);
mutex_exit(&vip->vdi_lock);
mutex_enter(&inst->vri_lock);
if (inst->vri_flags & VARPD_INSTANCE_F_ACTIVATED) {
inst->vri_flags &= ~VARPD_INSTANCE_F_ACTIVATED;
libvarpd_torch_instance(vip, inst);
inst->vri_plugin->vpp_ops->vpo_stop(inst->vri_private);
inst->vri_plugin->vpp_ops->vpo_destroy(inst->vri_private);
inst->vri_private = NULL;
}
mutex_exit(&inst->vri_lock);
if (mutex_destroy(&inst->vri_lock) != 0)
libvarpd_panic("failed to destroy instance vri_lock");
id_free(vip->vdi_idspace, inst->vri_id);
umem_free(inst, sizeof (varpd_instance_t));
}
int
libvarpd_instance_activate(varpd_instance_handle_t *ihp)
{
int ret;
varpd_instance_t *inst = (varpd_instance_t *)ihp;
mutex_enter(&inst->vri_lock);
if (inst->vri_flags & VARPD_INSTANCE_F_ACTIVATED) {
ret = EEXIST;
goto out;
}
if ((ret = inst->vri_plugin->vpp_ops->vpo_start(inst->vri_private)) !=
0)
goto out;
if ((ret = libvarpd_persist_instance(inst->vri_impl, inst)) != 0)
goto out;
if ((ret = libvarpd_overlay_associate(inst)) != 0)
goto out;
inst->vri_flags |= VARPD_INSTANCE_F_ACTIVATED;
out:
mutex_exit(&inst->vri_lock);
return (ret);
}
static void
libvarpd_prefork(void)
{
libvarpd_plugin_prefork();
}
static void
libvarpd_postfork(void)
{
libvarpd_plugin_postfork();
}
#pragma init(libvarpd_init)
static void
libvarpd_init(void)
{
libvarpd_plugin_init();
if (pthread_atfork(libvarpd_prefork, libvarpd_postfork,
libvarpd_postfork) != 0)
libvarpd_panic("failed to create varpd atfork: %d", errno);
}
#pragma fini(libvarpd_fini)
static void
libvarpd_fini(void)
{
libvarpd_plugin_fini();
}