diff options
Diffstat (limited to 'src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c')
-rw-r--r-- | src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c | 25 |
1 files changed, 17 insertions, 8 deletions
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c index 9d9f15974..3c1a3f87d 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c @@ -1975,6 +1975,8 @@ METHOD(kernel_net_t, add_ip, status_t, if (iface) { addr_entry_t *addr; + char *ifname; + int ifi; INIT(addr, .ip = virtual_ip->clone(virtual_ip), @@ -1983,26 +1985,30 @@ METHOD(kernel_net_t, add_ip, status_t, ); iface->addrs->insert_last(iface->addrs, addr); addr_map_entry_add(this->vips, addr, iface); + ifi = iface->ifindex; + this->lock->unlock(this->lock); if (manage_ipaddr(this, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL, - iface->ifindex, virtual_ip, prefix) == SUCCESS) + ifi, virtual_ip, prefix) == SUCCESS) { + this->lock->write_lock(this->lock); while (!is_vip_installed_or_gone(this, virtual_ip, &entry)) { /* wait until address appears */ 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); + ifname = strdup(entry->iface->ifname); this->lock->unlock(this->lock); + DBG2(DBG_KNL, "virtual IP %H installed on %s", + virtual_ip, ifname); /* during IKEv1 reauthentication, children get moved from * old the new SA before the virtual IP is available. This * kills the route for our virtual IP, reinstall. */ - queue_route_reinstall(this, strdup(entry->iface->ifname)); + queue_route_reinstall(this, ifname); return SUCCESS; } + this->lock->unlock(this->lock); } - this->lock->unlock(this->lock); DBG1(DBG_KNL, "adding virtual IP %H failed", virtual_ip); return FAILED; } @@ -2048,20 +2054,23 @@ METHOD(kernel_net_t, del_ip, status_t, if (entry->addr->refcount == 1) { status_t status; + int ifi; /* we set this flag so that threads calling add_ip will block and wait * until the entry is gone, also so we can wait below */ entry->addr->installed = FALSE; - status = manage_ipaddr(this, RTM_DELADDR, 0, entry->iface->ifindex, - virtual_ip, prefix); + ifi = entry->iface->ifindex; + this->lock->unlock(this->lock); + status = manage_ipaddr(this, RTM_DELADDR, 0, ifi, virtual_ip, prefix); if (status == SUCCESS && wait) { /* wait until the address is really gone */ + this->lock->write_lock(this->lock); while (is_known_vip(this, virtual_ip)) { this->condvar->wait(this->condvar, this->lock); } + this->lock->unlock(this->lock); } - this->lock->unlock(this->lock); return status; } else |