made add_ip()/del_ip() calls synchron (waiting until kernel event received)
this should fix MOBIKE route migration with virtual IPs
This commit is contained in:
parent
278396b6da
commit
983d7cd292
|
@ -34,6 +34,7 @@
|
|||
#include <linux/rtnetlink.h>
|
||||
#include <linux/xfrm.h>
|
||||
#include <linux/udp.h>
|
||||
#define __USE_UNIX98
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -304,6 +305,11 @@ struct private_kernel_interface_t {
|
|||
*/
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
/**
|
||||
* condition variable to signal virtual IP add/removal
|
||||
*/
|
||||
pthread_cond_t cond;
|
||||
|
||||
/**
|
||||
* List of installed policies (policy_entry_t)
|
||||
*/
|
||||
|
@ -725,8 +731,16 @@ static void process_addr(private_kernel_interface_t *this,
|
|||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -853,10 +867,12 @@ static job_requeue_t receive_events(private_kernel_interface_t *this)
|
|||
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:
|
||||
|
@ -1326,6 +1342,40 @@ static int get_interface_index(private_kernel_interface_t *this, host_t* ip)
|
|||
return ifindex;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@ -1652,6 +1702,7 @@ static status_t add_ip(private_kernel_interface_t *this,
|
|||
iface_entry_t *iface;
|
||||
addr_entry_t *addr;
|
||||
iterator_t *addrs, *ifaces;
|
||||
int ifindex;
|
||||
|
||||
DBG2(DBG_KNL, "adding virtual IP %H", virtual_ip);
|
||||
|
||||
|
@ -1681,26 +1732,28 @@ static status_t add_ip(private_kernel_interface_t *this,
|
|||
|
||||
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);
|
||||
|
||||
|
@ -1717,6 +1770,8 @@ static status_t del_ip(private_kernel_interface_t *this, host_t *virtual_ip)
|
|||
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);
|
||||
|
||||
|
@ -1728,16 +1783,25 @@ static status_t del_ip(private_kernel_interface_t *this, host_t *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);
|
||||
|
@ -2526,6 +2590,7 @@ kernel_interface_t *kernel_interface_create()
|
|||
{
|
||||
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;
|
||||
|
@ -2548,7 +2613,11 @@ kernel_interface_t *kernel_interface_create()
|
|||
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));
|
||||
|
|
Loading…
Reference in New Issue