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/rtnetlink.h>
|
||||||
#include <linux/xfrm.h>
|
#include <linux/xfrm.h>
|
||||||
#include <linux/udp.h>
|
#include <linux/udp.h>
|
||||||
|
#define __USE_UNIX98
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -304,6 +305,11 @@ struct private_kernel_interface_t {
|
||||||
*/
|
*/
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* condition variable to signal virtual IP add/removal
|
||||||
|
*/
|
||||||
|
pthread_cond_t cond;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of installed policies (policy_entry_t)
|
* List of installed policies (policy_entry_t)
|
||||||
*/
|
*/
|
||||||
|
@ -725,8 +731,16 @@ static void process_addr(private_kernel_interface_t *this,
|
||||||
{
|
{
|
||||||
changed = TRUE;
|
changed = TRUE;
|
||||||
addrs->remove(addrs);
|
addrs->remove(addrs);
|
||||||
|
if (!addr->virtual)
|
||||||
|
{
|
||||||
|
DBG1(DBG_KNL, "%H disappeared from %s",
|
||||||
|
host, iface->ifname);
|
||||||
|
}
|
||||||
addr_entry_destroy(addr);
|
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_NEWADDR:
|
||||||
case RTM_DELADDR:
|
case RTM_DELADDR:
|
||||||
process_addr(this, hdr, TRUE);
|
process_addr(this, hdr, TRUE);
|
||||||
|
pthread_cond_signal(&this->cond);
|
||||||
break;
|
break;
|
||||||
case RTM_NEWLINK:
|
case RTM_NEWLINK:
|
||||||
case RTM_DELLINK:
|
case RTM_DELLINK:
|
||||||
process_link(this, hdr, TRUE);
|
process_link(this, hdr, TRUE);
|
||||||
|
pthread_cond_signal(&this->cond);
|
||||||
break;
|
break;
|
||||||
case RTM_NEWROUTE:
|
case RTM_NEWROUTE:
|
||||||
case RTM_DELROUTE:
|
case RTM_DELROUTE:
|
||||||
|
@ -1326,6 +1342,40 @@ static int get_interface_index(private_kernel_interface_t *this, host_t* ip)
|
||||||
return ifindex;
|
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.
|
* Manages the creation and deletion of ip addresses on an interface.
|
||||||
* By setting the appropriate nlmsg_type, the ip will be set or unset.
|
* 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;
|
iface_entry_t *iface;
|
||||||
addr_entry_t *addr;
|
addr_entry_t *addr;
|
||||||
iterator_t *addrs, *ifaces;
|
iterator_t *addrs, *ifaces;
|
||||||
|
int ifindex;
|
||||||
|
|
||||||
DBG2(DBG_KNL, "adding virtual IP %H", virtual_ip);
|
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)
|
if (iface_found)
|
||||||
{
|
{
|
||||||
int ifindex = iface->ifindex;
|
ifindex = iface->ifindex;
|
||||||
ifaces->destroy(ifaces);
|
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,
|
if (manage_ipaddr(this, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL,
|
||||||
ifindex, virtual_ip) == SUCCESS)
|
ifindex, virtual_ip) == SUCCESS)
|
||||||
{
|
{
|
||||||
addr = malloc_thing(addr_entry_t);
|
while (get_vip_refcount(this, virtual_ip) == 0)
|
||||||
addr->ip = virtual_ip->clone(virtual_ip);
|
{ /* wait until address appears */
|
||||||
addr->refcount = 1;
|
pthread_cond_wait(&this->cond, &this->mutex);
|
||||||
addr->virtual = TRUE;
|
}
|
||||||
addr->scope = RT_SCOPE_UNIVERSE;
|
ifaces->destroy(ifaces);
|
||||||
pthread_mutex_lock(&this->mutex);
|
|
||||||
iface->addrs->insert_last(iface->addrs, addr);
|
|
||||||
pthread_mutex_unlock(&this->mutex);
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
ifaces->destroy(ifaces);
|
||||||
DBG1(DBG_KNL, "adding virtual IP %H failed", virtual_ip);
|
DBG1(DBG_KNL, "adding virtual IP %H failed", virtual_ip);
|
||||||
return FAILED;
|
return FAILED;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
ifaces->destroy(ifaces);
|
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;
|
iface_entry_t *iface;
|
||||||
addr_entry_t *addr;
|
addr_entry_t *addr;
|
||||||
iterator_t *addrs, *ifaces;
|
iterator_t *addrs, *ifaces;
|
||||||
|
status_t status;
|
||||||
|
int ifindex;
|
||||||
|
|
||||||
DBG2(DBG_KNL, "deleting virtual IP %H", virtual_ip);
|
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))
|
if (virtual_ip->ip_equals(virtual_ip, addr->ip))
|
||||||
{
|
{
|
||||||
int ifindex = iface->ifindex;
|
ifindex = iface->ifindex;
|
||||||
addr->refcount--;
|
if (addr->refcount == 1)
|
||||||
if (addr->refcount == 0)
|
|
||||||
{
|
{
|
||||||
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);
|
addrs->destroy(addrs);
|
||||||
ifaces->destroy(ifaces);
|
ifaces->destroy(ifaces);
|
||||||
addr_entry_destroy(addr);
|
return status;
|
||||||
return manage_ipaddr(this, RTM_DELADDR, 0,
|
}
|
||||||
ifindex, virtual_ip);
|
else
|
||||||
|
{
|
||||||
|
addr->refcount--;
|
||||||
}
|
}
|
||||||
DBG2(DBG_KNL, "virtual IP %H used by other SAs, not deleting",
|
DBG2(DBG_KNL, "virtual IP %H used by other SAs, not deleting",
|
||||||
virtual_ip);
|
virtual_ip);
|
||||||
|
@ -2526,6 +2590,7 @@ kernel_interface_t *kernel_interface_create()
|
||||||
{
|
{
|
||||||
private_kernel_interface_t *this = malloc_thing(private_kernel_interface_t);
|
private_kernel_interface_t *this = malloc_thing(private_kernel_interface_t);
|
||||||
struct sockaddr_nl addr;
|
struct sockaddr_nl addr;
|
||||||
|
pthread_mutexattr_t attr;
|
||||||
|
|
||||||
/* public functions */
|
/* 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->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->ifaces = linked_list_create();
|
||||||
this->hiter = NULL;
|
this->hiter = NULL;
|
||||||
this->seq = 200;
|
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);
|
timerclear(&this->last_roam);
|
||||||
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
|
Loading…
Reference in New Issue