#include <linux/rtnetlink.h>
#include <linux/xfrm.h>
#include <linux/udp.h>
+#define __USE_UNIX98
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
pthread_mutex_t mutex;
/**
+ * condition variable to signal virtual IP add/removal
+ */
+ pthread_cond_t cond;
+
+ /**
* List of installed policies (policy_entry_t)
*/
linked_list_t *policies;
{
changed = TRUE;
addrs->remove(addrs);
+ if (!addr->virtual)
+ {
+ DBG1(DBG_KNL, "%H disappeared from %s",
+ host, iface->ifname);
+ }
addr_entry_destroy(addr);
- DBG1(DBG_KNL, "%H disappeared from %s", host, iface->ifname);
+ }
+ else if (hdr->nlmsg_type == RTM_NEWADDR && addr->virtual)
+ {
+ addr->refcount = 1;
}
}
}
case RTM_NEWADDR:
case RTM_DELADDR:
process_addr(this, hdr, TRUE);
+ pthread_cond_signal(&this->cond);
break;
case RTM_NEWLINK:
case RTM_DELLINK:
process_link(this, hdr, TRUE);
+ pthread_cond_signal(&this->cond);
break;
case RTM_NEWROUTE:
case RTM_DELROUTE:
}
/**
+ * get the refcount of a virtual ip
+ */
+static int get_vip_refcount(private_kernel_interface_t *this, host_t* ip)
+{
+ iterator_t *ifaces, *addrs;
+ iface_entry_t *iface;
+ addr_entry_t *addr;
+ int refcount = 0;
+
+ ifaces = this->ifaces->create_iterator(this->ifaces, TRUE);
+ while (ifaces->iterate(ifaces, (void**)&iface))
+ {
+ addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
+ while (addrs->iterate(addrs, (void**)&addr))
+ {
+ if (addr->virtual && (iface->flags & IFF_UP) &&
+ ip->ip_equals(ip, addr->ip))
+ {
+ refcount = addr->refcount;
+ break;
+ }
+ }
+ addrs->destroy(addrs);
+ if (refcount)
+ {
+ break;
+ }
+ }
+ ifaces->destroy(ifaces);
+
+ return refcount;
+}
+
+/**
* Manages the creation and deletion of ip addresses on an interface.
* By setting the appropriate nlmsg_type, the ip will be set or unset.
*/
iface_entry_t *iface;
addr_entry_t *addr;
iterator_t *addrs, *ifaces;
+ int ifindex;
DBG2(DBG_KNL, "adding virtual IP %H", virtual_ip);
if (iface_found)
{
- int ifindex = iface->ifindex;
- ifaces->destroy(ifaces);
+ ifindex = iface->ifindex;
+ addr = malloc_thing(addr_entry_t);
+ addr->ip = virtual_ip->clone(virtual_ip);
+ addr->refcount = 0;
+ addr->virtual = TRUE;
+ addr->scope = RT_SCOPE_UNIVERSE;
+ iface->addrs->insert_last(iface->addrs, addr);
+
if (manage_ipaddr(this, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL,
ifindex, virtual_ip) == SUCCESS)
{
- addr = malloc_thing(addr_entry_t);
- addr->ip = virtual_ip->clone(virtual_ip);
- addr->refcount = 1;
- addr->virtual = TRUE;
- addr->scope = RT_SCOPE_UNIVERSE;
- pthread_mutex_lock(&this->mutex);
- iface->addrs->insert_last(iface->addrs, addr);
- pthread_mutex_unlock(&this->mutex);
+ while (get_vip_refcount(this, virtual_ip) == 0)
+ { /* wait until address appears */
+ pthread_cond_wait(&this->cond, &this->mutex);
+ }
+ ifaces->destroy(ifaces);
return SUCCESS;
}
+ ifaces->destroy(ifaces);
DBG1(DBG_KNL, "adding virtual IP %H failed", virtual_ip);
return FAILED;
-
}
-
}
ifaces->destroy(ifaces);
iface_entry_t *iface;
addr_entry_t *addr;
iterator_t *addrs, *ifaces;
+ status_t status;
+ int ifindex;
DBG2(DBG_KNL, "deleting virtual IP %H", virtual_ip);
{
if (virtual_ip->ip_equals(virtual_ip, addr->ip))
{
- int ifindex = iface->ifindex;
- addr->refcount--;
- if (addr->refcount == 0)
+ ifindex = iface->ifindex;
+ if (addr->refcount == 1)
{
- addrs->remove(addrs);
+ status = manage_ipaddr(this, RTM_DELADDR, 0,
+ ifindex, virtual_ip);
+ if (status == SUCCESS)
+ { /* wait until the address is really gone */
+ while (get_vip_refcount(this, virtual_ip) > 0)
+ {
+ pthread_cond_wait(&this->cond, &this->mutex);
+ }
+ }
addrs->destroy(addrs);
ifaces->destroy(ifaces);
- addr_entry_destroy(addr);
- return manage_ipaddr(this, RTM_DELADDR, 0,
- ifindex, virtual_ip);
+ return status;
+ }
+ else
+ {
+ addr->refcount--;
}
DBG2(DBG_KNL, "virtual IP %H used by other SAs, not deleting",
virtual_ip);
{
private_kernel_interface_t *this = malloc_thing(private_kernel_interface_t);
struct sockaddr_nl addr;
+ pthread_mutexattr_t attr;
/* public functions */
this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
this->ifaces = linked_list_create();
this->hiter = NULL;
this->seq = 200;
- pthread_mutex_init(&this->mutex,NULL);
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&this->mutex, &attr);
+ pthread_mutexattr_destroy(&attr);
+ pthread_cond_init(&this->cond, NULL);
timerclear(&this->last_roam);
memset(&addr, 0, sizeof(addr));