diff options
author | Tobias Brunner <tobias@strongswan.org> | 2012-09-20 18:21:42 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2012-09-21 18:16:27 +0200 |
commit | a25d536eeab400e89b49ce75f052cd279b6c2aa7 (patch) | |
tree | 79651e66a4c3210ff215c4dc631cc5f26edd9592 /src | |
parent | 16d62305c209baacb5139dbf5adf7ef0ff405226 (diff) | |
download | strongswan-a25d536eeab400e89b49ce75f052cd279b6c2aa7.tar.bz2 strongswan-a25d536eeab400e89b49ce75f052cd279b6c2aa7.tar.xz |
Use rwlock and rwlock_condvar to increase concurrency in kernel-netlink plugin
Diffstat (limited to 'src')
-rw-r--r-- | src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c | 113 |
1 files changed, 55 insertions, 58 deletions
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c index 4b64a8d26..3f63a8496 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c @@ -51,8 +51,9 @@ #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> @@ -339,14 +340,14 @@ struct private_kernel_netlink_net_t { 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) @@ -563,7 +564,7 @@ static void queue_route_reinstall(private_kernel_netlink_net_t *this, * 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) @@ -584,7 +585,7 @@ static bool is_vip_installed_or_gone(private_kernel_netlink_net_t *this, /** * 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) { @@ -634,6 +635,8 @@ static void addr_map_entry_remove(hashtable_t *map, addr_entry_t *addr, * 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) @@ -643,7 +646,6 @@ static host_t *get_interface_address(private_kernel_netlink_net_t *this, 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) { @@ -674,12 +676,7 @@ static host_t *get_interface_address(private_kernel_netlink_net_t *this, addrs->destroy(addrs); } } - if (ip) - { - ip = ip->clone(ip); - } - this->mutex->unlock(this->mutex); - return ip; + return ip ? ip->clone(ip) : NULL; } /** @@ -725,7 +722,7 @@ static void fire_roam_event(private_kernel_netlink_net_t *this, bool address) /** * 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) @@ -743,7 +740,7 @@ static bool is_interface_up_and_usable(private_kernel_netlink_net_t *this, /** * 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) @@ -786,7 +783,7 @@ static void process_link(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: @@ -846,7 +843,7 @@ static void process_link(private_kernel_netlink_net_t *this, break; } } - this->mutex->unlock(this->mutex); + this->lock->unlock(this->lock); if (update_routes && event) { @@ -907,7 +904,7 @@ static void process_addr(private_kernel_netlink_net_t *this, 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) { @@ -933,7 +930,7 @@ static void process_addr(private_kernel_netlink_net_t *this, } /* 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; } @@ -983,7 +980,7 @@ static void process_addr(private_kernel_netlink_net_t *this, update = changed = FALSE; } } - this->mutex->unlock(this->mutex); + this->lock->unlock(this->lock); if (update && event && route_ifname) { @@ -1042,10 +1039,10 @@ static void process_route(private_kernel_netlink_net_t *this, struct nlmsghdr *h } 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; } @@ -1053,15 +1050,15 @@ static void process_route(private_kernel_netlink_net_t *this, struct nlmsghdr *h { 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); } /** @@ -1143,7 +1140,7 @@ typedef struct { */ 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); } @@ -1205,7 +1202,7 @@ METHOD(kernel_net_t, create_address_enumerator, enumerator_t*, 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), @@ -1225,7 +1222,7 @@ METHOD(kernel_net_t, get_interface_name, bool, { 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); @@ -1236,7 +1233,7 @@ METHOD(kernel_net_t, get_interface_name, bool, *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 */ @@ -1246,7 +1243,7 @@ METHOD(kernel_net_t, get_interface_name, bool, { 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; } @@ -1260,13 +1257,13 @@ static int get_interface_index(private_kernel_netlink_net_t *this, char* name) 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) { @@ -1446,7 +1443,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest, 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)) @@ -1601,7 +1598,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest, 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); @@ -1676,7 +1673,7 @@ METHOD(kernel_net_t, add_ip, status_t, 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, @@ -1690,12 +1687,12 @@ METHOD(kernel_net_t, add_ip, status_t, * 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) { @@ -1707,7 +1704,7 @@ METHOD(kernel_net_t, add_ip, status_t, { 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 */ @@ -1743,21 +1740,21 @@ METHOD(kernel_net_t, add_ip, status_t, { 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; @@ -1777,7 +1774,7 @@ METHOD(kernel_net_t, del_ip, status_t, 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) @@ -1788,11 +1785,11 @@ METHOD(kernel_net_t, del_ip, status_t, { 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) @@ -1808,10 +1805,10 @@ METHOD(kernel_net_t, del_ip, status_t, { /* 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 @@ -1820,7 +1817,7 @@ METHOD(kernel_net_t, del_ip, status_t, } 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; } @@ -2018,7 +2015,7 @@ static status_t init_address_list(private_kernel_netlink_net_t *this) } 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)) { @@ -2034,7 +2031,7 @@ static status_t init_address_list(private_kernel_netlink_net_t *this) } } ifaces->destroy(ifaces); - this->mutex->unlock(this->mutex); + this->lock->unlock(this->lock); return SUCCESS; } @@ -2159,7 +2156,7 @@ METHOD(kernel_net_t, destroy, void, 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); } @@ -2202,8 +2199,8 @@ kernel_netlink_net_t *kernel_netlink_net_create() .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), |