#include <hydra.h>
#include <debug.h>
#include <threading/thread.h>
-#include <threading/condvar.h>
#include <threading/mutex.h>
+#include <threading/rwlock.h>
+#include <threading/rwlock_condvar.h>
#include <threading/spinlock.h>
#include <utils/hashtable.h>
#include <utils/linked_list.h>
kernel_netlink_net_t public;
/**
- * mutex to lock access to various lists
+ * lock to access various lists and maps
*/
- mutex_t *mutex;
+ rwlock_t *lock;
/**
* condition variable to signal virtual IP add/removal
*/
- condvar_t *condvar;
+ rwlock_condvar_t *condvar;
/**
* Cached list of interfaces and its addresses (iface_entry_t)
* this function will also return TRUE if the virtual IP entry disappeared.
* in that case the returned entry will be NULL.
*
- * this->mutex must be locked when calling this function
+ * this->lock must be held when calling this function
*/
static bool is_vip_installed_or_gone(private_kernel_netlink_net_t *this,
host_t *ip, addr_map_entry_t **entry)
/**
* check if the given IP is known as virtual IP
*
- * this->mutex must be locked when calling this function
+ * this->lock must be held when calling this function
*/
static bool is_known_vip(private_kernel_netlink_net_t *this, host_t *ip)
{
* if a candidate address is given, we first search for that address and if not
* found return the address as above.
* returned host is a clone, has to be freed by caller.
+ *
+ * this->lock must be held when calling this function
*/
static host_t *get_interface_address(private_kernel_netlink_net_t *this,
int ifindex, int family, host_t *candidate)
addr_entry_t *addr;
host_t *ip = NULL;
- this->mutex->lock(this->mutex);
if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_index,
(void**)&iface, &ifindex) == SUCCESS)
{
addrs->destroy(addrs);
}
}
- if (ip)
- {
- ip = ip->clone(ip);
- }
- this->mutex->unlock(this->mutex);
- return ip;
+ return ip ? ip->clone(ip) : NULL;
}
/**
/**
* check if an interface with a given index is up and usable
*
- * this->mutex must be locked when calling this function
+ * this->lock must be locked when calling this function
*/
static bool is_interface_up_and_usable(private_kernel_netlink_net_t *this,
int index)
/**
* unregister the current addr_entry_t from the hashtable it is stored in
*
- * this->mutex must be locked when calling this function
+ * this->lock must be locked when calling this function
*/
static void addr_entry_unregister(addr_entry_t *addr, iface_entry_t *iface,
private_kernel_netlink_net_t *this)
name = "(unknown)";
}
- this->mutex->lock(this->mutex);
+ this->lock->write_lock(this->lock);
switch (hdr->nlmsg_type)
{
case RTM_NEWLINK:
break;
}
}
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
if (update_routes && event)
{
return;
}
- this->mutex->lock(this->mutex);
+ this->lock->write_lock(this->lock);
if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_index,
(void**)&iface, &msg->ifa_index) == SUCCESS)
{
}
/* no roam events etc. for virtual IPs */
this->condvar->broadcast(this->condvar);
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
host->destroy(host);
return;
}
update = changed = FALSE;
}
}
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
if (update && event && route_ifname)
{
}
rta = RTA_NEXT(rta, rtasize);
}
- this->mutex->lock(this->mutex);
+ this->lock->read_lock(this->lock);
if (rta_oif && !is_interface_up_and_usable(this, rta_oif))
{ /* ignore route changes for interfaces that are ignored or down */
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
DESTROY_IF(host);
return;
}
{
host = get_interface_address(this, rta_oif, msg->rtm_family, NULL);
}
- if (host)
- {
- if (!is_known_vip(this, host))
- { /* ignore routes added for virtual IPs */
- fire_roam_event(this, FALSE);
- }
- host->destroy(host);
+ if (!host || is_known_vip(this, host))
+ { /* ignore routes added for virtual IPs */
+ this->lock->unlock(this->lock);
+ DESTROY_IF(host);
+ return;
}
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
+ fire_roam_event(this, FALSE);
+ host->destroy(host);
}
/**
*/
static void address_enumerator_destroy(address_enumerator_t *data)
{
- data->this->mutex->unlock(data->this->mutex);
+ data->this->lock->unlock(data->this->lock);
free(data);
}
data->this = this;
data->which = which;
- this->mutex->lock(this->mutex);
+ this->lock->read_lock(this->lock);
return enumerator_create_nested(
enumerator_create_filter(
this->ifaces->create_enumerator(this->ifaces),
{
return FALSE;
}
- this->mutex->lock(this->mutex);
+ this->lock->read_lock(this->lock);
/* first try to find it on an up and usable interface */
entry = this->addrs->get_match(this->addrs, &lookup,
(void*)addr_map_entry_match_up_and_usable);
*name = strdup(entry->iface->ifname);
DBG2(DBG_KNL, "%H is on interface %s", ip, *name);
}
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
return TRUE;
}
/* maybe it is installed on an ignored interface */
{
DBG2(DBG_KNL, "%H is not a local address or the interface is down", ip);
}
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
return FALSE;
}
DBG2(DBG_KNL, "getting iface index for %s", name);
- this->mutex->lock(this->mutex);
+ this->lock->read_lock(this->lock);
if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_name,
(void**)&iface, name) == SUCCESS)
{
ifindex = iface->ifindex;
}
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
if (ifindex == 0)
{
return NULL;
}
routes = linked_list_create();
- this->mutex->lock(this->mutex);
+ this->lock->read_lock(this->lock);
for (current = out; NLMSG_OK(current, len);
current = NLMSG_NEXT(current, len))
addr = best->src_host->clone(best->src_host);
}
}
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
routes->destroy_function(routes, (void*)rt_entry_destroy);
free(out);
return SUCCESS;
}
- this->mutex->lock(this->mutex);
+ this->lock->write_lock(this->lock);
/* the virtual IP might actually be installed as regular IP, in which case
* we don't track it as virtual IP */
entry = this->addrs->get_match(this->addrs, &lookup,
* ready, 2) just added by another thread, but not yet confirmed to
* be installed by the kernel, 3) just deleted, but not yet gone.
* Then while we wait below, several things could happen (as we
- * release the mutex). For instance, the interface could disappear,
+ * release the lock). For instance, the interface could disappear,
* or the IP is finally deleted, and it reappears on a different
* interface. All these cases are handled by the call below. */
while (!is_vip_installed_or_gone(this, virtual_ip, &entry))
{
- this->condvar->wait(this->condvar, this->mutex);
+ this->condvar->wait(this->condvar, this->lock);
}
if (entry)
{
{
DBG2(DBG_KNL, "virtual IP %H is already installed on %s", virtual_ip,
entry->iface->ifname);
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
return SUCCESS;
}
/* try to find the target interface, either by config or via src ip */
{
while (!is_vip_installed_or_gone(this, virtual_ip, &entry))
{ /* wait until address appears */
- this->condvar->wait(this->condvar, this->mutex);
+ this->condvar->wait(this->condvar, this->lock);
}
if (entry)
{ /* we fail if the interface got deleted in the meantime */
DBG2(DBG_KNL, "virtual IP %H installed on %s", virtual_ip,
entry->iface->ifname);
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
return SUCCESS;
}
}
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
DBG1(DBG_KNL, "adding virtual IP %H failed", virtual_ip);
return FAILED;
}
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
DBG1(DBG_KNL, "no interface available, unable to install virtual IP %H",
virtual_ip);
return FAILED;
DBG2(DBG_KNL, "deleting virtual IP %H", virtual_ip);
- this->mutex->lock(this->mutex);
+ this->lock->write_lock(this->lock);
entry = this->vips->get_match(this->vips, &lookup,
(void*)addr_map_entry_match);
if (!entry)
{
DBG2(DBG_KNL, "not deleting existing IP %H on %s", virtual_ip,
entry->iface->ifname);
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
return SUCCESS;
}
DBG2(DBG_KNL, "virtual IP %H not cached, unable to delete", virtual_ip);
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
return FAILED;
}
if (entry->addr->refcount == 1)
{ /* wait until the address is really gone */
while (is_known_vip(this, virtual_ip))
{
- this->condvar->wait(this->condvar, this->mutex);
+ this->condvar->wait(this->condvar, this->lock);
}
}
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
return status;
}
else
}
DBG2(DBG_KNL, "virtual IP %H used by other SAs, not deleting",
virtual_ip);
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
return SUCCESS;
}
}
free(out);
- this->mutex->lock(this->mutex);
+ this->lock->read_lock(this->lock);
ifaces = this->ifaces->create_enumerator(this->ifaces);
while (ifaces->enumerate(ifaces, &iface))
{
}
}
ifaces->destroy(ifaces);
- this->mutex->unlock(this->mutex);
+ this->lock->unlock(this->lock);
return SUCCESS;
}
this->rt_exclude->destroy(this->rt_exclude);
this->roam_lock->destroy(this->roam_lock);
this->condvar->destroy(this->condvar);
- this->mutex->destroy(this->mutex);
+ this->lock->destroy(this->lock);
free(this);
}
.routes_lock = mutex_create(MUTEX_TYPE_DEFAULT),
.net_changes_lock = mutex_create(MUTEX_TYPE_DEFAULT),
.ifaces = linked_list_create(),
- .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
- .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ .condvar = rwlock_condvar_create(),
.roam_lock = spinlock_create(),
.routing_table = lib->settings->get_int(lib->settings,
"%s.routing_table", ROUTING_TABLE, hydra->daemon),