1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-01-22 22:03:39 +03:00

Bug #4516: Fix deadlock with concurrent reservations on the same

vnet.
This commit is contained in:
Ruben S. Montero 2016-06-03 19:16:51 +02:00
parent 234e7b410c
commit 57976f61c2
5 changed files with 365 additions and 134 deletions

View File

@ -364,49 +364,52 @@ public:
// *************************************************************************
/**
* Reserve an address range for this network and add it to the given vnet
* @param rvnet the VNET to store the reserved AR
* Reserve an address range for this network and add it to the given AR
* @param rid the reservation VNET ID to store the reserved AR
* @param rsize number of addresses to reserve
* @param error_str error message
* @param rar the address range to place the reservation
* @param err error message
* @return 0 on success
*/
int reserve_addr(VirtualNetwork *rvnet, unsigned int rsize,
string& error_str);
int reserve_addr(int rid, unsigned int rsize, AddressRange *rar, string& err);
/**
* Reserve an address range for this network and add it to the given AR
* @param rid the reservation VNET ID to store the reserved AR
* @param rsize number of addresses to reserve
* @param ar_id of the ar to make the reservation from
* @param rar the address range to place the reservation
* @param err error message
* @return 0 on success
*/
int reserve_addr(int rid, unsigned int rsize, unsigned int ar_id,
AddressRange *rar, string& error_str);
/**
* Reserve an address range for this network and add it to the given vnet
* @param rvnet the VNET to store the reserved AR
* @param rid the reservation VNET ID to store the reserved AR
* @param rsize number of addresses to reserve
* @param ar_id id of the address range to obtain the addresses
* @param error_str error message
* @return 0 on success
*/
int reserve_addr(VirtualNetwork *rvnet, unsigned int rsize,
unsigned int ar_id, string& error_str);
/**
* Reserve an address range for this network and add it to the given vnet
* @param rvnet the VNET to store the reserved AR
* @param rsize number of addresses to reserve
* @param ar_id id of the address range to obtain the addresses
* @param error_str error message
* @param ip the first ip in the reservations
* @param rar the address range to place the reservation
* @param err error message
* @return 0 on success
*/
int reserve_addr_by_ip(VirtualNetwork *rvnet, unsigned int rsize,
unsigned int ar_id, const string& ip, string& error_str);
int reserve_addr_by_ip(int rid, unsigned int rsize, unsigned int ar_id,
const string& ip, AddressRange *rar, string& error_str);
/**
* Reserve an address range for this network and add it to the given vnet
* @param rvnet the VNET to store the reserved AR
* @param rid the reservation VNET ID to store the reserved AR
* @param rsize number of addresses to reserve
* @param ar_id id of the address range to obtain the addresses
* @param mac the first mac in the reservations
* @param error_str error message
* @param rar the address range to place the reservation
* @param err error message
* @return 0 on success
*/
int reserve_addr_by_mac(VirtualNetwork *rvnet, unsigned int rsize,
unsigned int ar_id, const string& mac, string& error_str);
int reserve_addr_by_mac(int rid, unsigned int rsize, unsigned int ar_id,
const string& mac, AddressRange *rar, string& error_str);
/**
* Returns true if this VNET is a reservation

View File

@ -203,6 +203,56 @@ public:
VectorAttribute * nic,
int uid,
AuthRequest * ar);
//--------------------------------------------------------------------------
// VNET Reservation interface
//--------------------------------------------------------------------------
/**
* Reserve an address range
* @param pid the parent VNET ID to get the leases from
* @param rid the reservation VNET ID to store the reserved AR
* @param rsize number of addresses to reserve
* @param err error message
* @return 0 on success
*/
int reserve_addr(int pid, int rid, unsigned int rsize, string& err);
/**
* Reserve an address range
* @param pid the parent VNET ID to get the leases from
* @param rid the reservation VNET ID to store the reserved AR
* @param rsize number of addresses to reserve
* @param ar_id AR to make the reservation from
* @param err error message
* @return 0 on success
*/
int reserve_addr(int pid, int rid, unsigned int rsize, unsigned int ar_id,
string& err);
/**
* Reserve an address range
* @param pid the parent VNET ID to get the leases from
* @param rid the reservation VNET ID to store the reserved AR
* @param rsize number of addresses to reserve
* @param ar_id AR to make the reservation from
* @param ip the first ip in the reservations
* @param err error message
* @return 0 on success
*/
int reserve_addr_by_ip(int pid, int rid, unsigned int rsize,
unsigned int ar_id, const string& ip, string& err);
/**
* Reserve an address range
* @param pid the parent VNET ID to get the leases from
* @param rid the reservation VNET ID to store the reserved AR
* @param rsize number of addresses to reserve
* @param ar_id AR to make the reservation from
* @param mac the first mac in the reservations
* @param err error message
* @return 0 on success
*/
int reserve_addr_by_mac(int pid, int rid, unsigned int rsize,
unsigned int ar_id, const string& mac, string& err);
private:
/**
* Holds the system-wide MAC prefix
@ -277,6 +327,26 @@ private:
*/
void release_vlan_id(VirtualNetwork *vn);
//--------------------------------------------------------------------------
// VNET Reservation Functions
//--------------------------------------------------------------------------
/**
* Allocate a new AR from the given VNET
* @param rid VNET ID
* @param err string if any
* @return pointer to the allocated AR
*/
AddressRange * allocate_ar(int rid, string &err);
/**
* Adds a new AR to a VNET
* @param rid VNET ID
* @param ar pointer to the AR
* @param err string if any
* @return 0 on success
*/
int add_ar(int rid, AddressRange *rar, string &err);
/**
* Factory method to produce VN objects
* @return a pointer to the new VN

View File

@ -186,6 +186,8 @@ void VirtualNetworkReserve::request_execute(
int rc;
set<int> cluster_ids;
VirtualNetworkTemplate * vtmpl;
PoolObjectAuth reserv_perms;
// -------------------------------------------------------------------------
@ -330,7 +332,6 @@ void VirtualNetworkReserve::request_execute(
failure_response(ACTION, att);
vn->unlock();
return;
}
@ -345,14 +346,19 @@ void VirtualNetworkReserve::request_execute(
{
ar.add_auth(AuthRequest::MANAGE, reserv_perms);
}
else
{
vtmpl = vn->clone_template();
cluster_ids = vn->get_cluster_ids();
}
vn->unlock();
if (UserPool::authorize(ar) == -1)
{
att.resp_msg = ar.message;
failure_response(AUTHORIZATION, att);
vn->unlock();
return;
}
@ -361,21 +367,14 @@ void VirtualNetworkReserve::request_execute(
// -------------------------------------------------------------------------
if (!on_exisiting)
{
VirtualNetworkTemplate * vtmpl = vn->clone_template();
vtmpl->replace("NAME", name);
cluster_ids = vn->get_cluster_ids();
rc = vnpool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask,
id, vtmpl, &rid, cluster_ids, att.resp_msg);
if (rc < 0)
{
failure_response(INTERNAL, att);
vn->unlock();
return;
}
}
@ -386,18 +385,22 @@ void VirtualNetworkReserve::request_execute(
{
att.resp_id = rid;
failure_response(NO_EXISTS, att);
vn->unlock();
return;
}
int ruid = rvn->get_uid();
int rgid = rvn->get_gid();
rvn->unlock();
// -------------------------------------------------------------------------
// Check & update quotas on the target VNET & *reservation owner*
// -------------------------------------------------------------------------
ostringstream qtmpl_s;
Template qtmpl;
RequestAttributes reservation_att(rvn->get_uid(), rvn->get_gid(), att);
RequestAttributes reservation_att(ruid, rgid, att);
for (int i=0; i< size ; i++)
{
@ -408,10 +411,6 @@ void VirtualNetworkReserve::request_execute(
if (quota_authorization(&qtmpl, Quotas::NETWORK, reservation_att) == false)
{
rvn->unlock();
vn->unlock();
return;
}
@ -422,20 +421,20 @@ void VirtualNetworkReserve::request_execute(
{
if (!ip.empty())
{
rc = vn->reserve_addr_by_ip(rvn, size, ar_id, ip, att.resp_msg);
rc = vnpool->reserve_addr_by_ip(id, rid, size, ar_id, ip, att.resp_msg);
}
else if (!mac.empty())
{
rc = vn->reserve_addr_by_mac(rvn, size, ar_id, mac, att.resp_msg);
rc = vnpool->reserve_addr_by_mac(id, rid, size, ar_id, mac, att.resp_msg);
}
else
{
rc = vn->reserve_addr(rvn, size, ar_id, att.resp_msg);
rc = vnpool->reserve_addr(id, rid, size, ar_id, att.resp_msg);
}
}
else
{
rc = vn->reserve_addr(rvn, size, att.resp_msg);
rc = vnpool->reserve_addr(id, rid, size, att.resp_msg);
}
if (rc != 0 )
@ -446,24 +445,17 @@ void VirtualNetworkReserve::request_execute(
if (!on_exisiting)
{
pool->drop(rvn, att.resp_msg);
rvn = vnpool->get(rid, true);
if (rvn != 0)
{
vnpool->drop(rvn, att.resp_msg);
}
}
rvn->unlock();
vn->unlock();
return;
}
pool->update(rvn);
pool->update(vn);
rvn->unlock();
vn->unlock();
// -------------------------------------------------------------------------
// Add the reservation to the same clusters as the parent VNET
// -------------------------------------------------------------------------

View File

@ -955,25 +955,33 @@ int VirtualNetwork::get_template_attribute(const char * name, int& value,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualNetwork::reserve_addr(VirtualNetwork *rvnet,
unsigned int rsize, string& error_str)
int VirtualNetwork::reserve_addr(int rid, unsigned int rsize, AddressRange *rar,
string& error_str)
{
AddressRange *rar = rvnet->allocate_ar();
if (ar_pool.reserve_addr(rvnet->get_oid(), rsize, rar) != 0)
if (ar_pool.reserve_addr(rid, rsize, rar) != 0)
{
error_str = "Not enough free addresses in an address range";
delete rar;
return -1;
}
if (rvnet->add_ar(rar) != 0)
{
error_str = "Could not add the address range to the netwok";
return 0;
}
delete rar;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualNetwork::reserve_addr(int rid, unsigned int rsize, unsigned int ar_id,
AddressRange *rar, string& error_str)
{
if (ar_pool.reserve_addr(rid, rsize, ar_id, rar) != 0)
{
ostringstream oss;
oss << "Not enough free addresses in address range " << ar_id
<< ", or it does not exist";
error_str = oss.str();
return -1;
}
@ -984,12 +992,10 @@ int VirtualNetwork::reserve_addr(VirtualNetwork *rvnet,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualNetwork::reserve_addr(VirtualNetwork *rvnet,
unsigned int rsize, unsigned int ar_id, string& error_str)
int VirtualNetwork::reserve_addr_by_ip(int rid, unsigned int rsize,
unsigned int ar_id, const string& ip, AddressRange *rar, string& error_str)
{
AddressRange *rar = rvnet->allocate_ar();
if (ar_pool.reserve_addr(rvnet->get_oid(), rsize, ar_id, rar) != 0)
if (ar_pool.reserve_addr_by_ip(rid, rsize, ar_id, ip, rar)!=0)
{
ostringstream oss;
@ -998,17 +1004,6 @@ int VirtualNetwork::reserve_addr(VirtualNetwork *rvnet,
error_str = oss.str();
delete rar;
return -1;
}
if (rvnet->add_ar(rar) != 0)
{
error_str = "Could not add the address range to the netwok";
delete rar;
return -1;
}
@ -1018,12 +1013,10 @@ int VirtualNetwork::reserve_addr(VirtualNetwork *rvnet,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualNetwork::reserve_addr_by_ip(VirtualNetwork *rvnet,
unsigned int rsize, unsigned int ar_id, const string& ip, string& error_str)
int VirtualNetwork::reserve_addr_by_mac(int rid, unsigned int rsize,
unsigned int ar_id, const string& mac, AddressRange *rar, string& error_str)
{
AddressRange *rar = rvnet->allocate_ar();
if (ar_pool.reserve_addr_by_ip(rvnet->get_oid(),rsize,ar_id,ip,rar)!=0)
if (ar_pool.reserve_addr_by_mac(rid, rsize, ar_id, mac, rar)!=0)
{
ostringstream oss;
@ -1032,51 +1025,6 @@ int VirtualNetwork::reserve_addr_by_ip(VirtualNetwork *rvnet,
error_str = oss.str();
delete rar;
return -1;
}
if (rvnet->add_ar(rar) != 0)
{
error_str = "Could not add the address range to the netwok";
delete rar;
return -1;
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualNetwork::reserve_addr_by_mac(VirtualNetwork *rvnet,
unsigned int rsize, unsigned int ar_id, const string& mac, string& error_str)
{
AddressRange *rar = rvnet->allocate_ar();
if (ar_pool.reserve_addr_by_mac(rvnet->get_oid(),rsize,ar_id,mac,rar)!=0)
{
ostringstream oss;
oss << "Not enough free addresses in address range " << ar_id
<< ", or it does not exist";
error_str = oss.str();
delete rar;
return -1;
}
if (rvnet->add_ar(rar) != 0)
{
error_str = "Could not add the address range to the netwok";
delete rar;
return -1;
}

View File

@ -480,3 +480,221 @@ void VirtualNetworkPool::release_vlan_id(VirtualNetwork *vn)
break;
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
AddressRange * VirtualNetworkPool::allocate_ar(int rid, string &err)
{
VirtualNetwork * rvn = get(rid, true);
if ( rvn == 0 )
{
ostringstream oss;
oss << "Virtual network " << rid << " does not exist";
err = oss.str();
return 0;
}
AddressRange *ar = rvn->allocate_ar();
update(rvn);
rvn->unlock();
return ar;
}
int VirtualNetworkPool::add_ar(int rid, AddressRange *rar, string &err)
{
VirtualNetwork * rvn = get(rid, true);
if ( rvn == 0 )
{
delete rar;
ostringstream oss;
oss << "Virtual network " << rid << " does not exist";
err = oss.str();
return -1;
}
int rc = rvn->add_ar(rar);
update(rvn);
rvn->unlock();
if ( rc != 0 )
{
delete rar;
err = "Could not add the address range to the netwok";
return -1;
}
return 0;
}
/* -------------------------------------------------------------------------- */
int VirtualNetworkPool::reserve_addr(int pid, int rid, unsigned int rsize, string& err)
{
AddressRange * rar = allocate_ar(rid, err);
if ( rar == 0 )
{
return -1;
}
VirtualNetwork * pvn = get(pid, true);
if ( pvn == 0 )
{
delete rar;
ostringstream oss;
oss << "Virtual network " << pid << " does not exist";
err = oss.str();
return -1;
}
int rc = pvn->reserve_addr(rid, rsize, rar, err);
update(pvn);
pvn->unlock();
if ( rc != 0)
{
delete rar;
return -1;
}
return add_ar(rid, rar, err);
}
/* -------------------------------------------------------------------------- */
int VirtualNetworkPool::reserve_addr(int pid, int rid, unsigned int rsize, unsigned int ar_id,
string& err)
{
AddressRange * rar = allocate_ar(rid, err);
if ( rar == 0 )
{
return -1;
}
VirtualNetwork * pvn = get(pid, true);
if ( pvn == 0 )
{
delete rar;
ostringstream oss;
oss << "Virtual network " << pid << " does not exist";
err = oss.str();
return -1;
}
int rc = pvn->reserve_addr(rid, rsize, ar_id, rar, err);
update(pvn);
pvn->unlock();
if ( rc != 0)
{
delete rar;
return -1;
}
return add_ar(rid, rar, err);
}
/* -------------------------------------------------------------------------- */
int VirtualNetworkPool::reserve_addr_by_ip(int pid, int rid, unsigned int rsize, unsigned int ar_id,
const string& ip, string& err)
{
AddressRange * rar = allocate_ar(rid, err);
if ( rar == 0 )
{
return -1;
}
VirtualNetwork * pvn = get(pid, true);
if ( pvn == 0 )
{
delete rar;
ostringstream oss;
oss << "Virtual network " << pid << " does not exist";
err = oss.str();
return -1;
}
int rc = pvn->reserve_addr_by_ip(rid, rsize, ar_id, ip, rar, err);
update(pvn);
pvn->unlock();
if ( rc != 0)
{
delete rar;
return -1;
}
return add_ar(rid, rar, err);
}
/* -------------------------------------------------------------------------- */
int VirtualNetworkPool::reserve_addr_by_mac(int pid, int rid, unsigned int rsize, unsigned int ar_id,
const string& mac, string& err)
{
AddressRange * rar = allocate_ar(rid, err);
if ( rar == 0 )
{
return -1;
}
VirtualNetwork * pvn = get(pid, true);
if ( pvn == 0 )
{
delete rar;
ostringstream oss;
oss << "Virtual network " << pid << " does not exist";
err = oss.str();
return -1;
}
int rc = pvn->reserve_addr_by_mac(rid, rsize, ar_id, mac, rar, err);
update(pvn);
pvn->unlock();
if ( rc != 0)
{
delete rar;
return -1;
}
return add_ar(rid, rar, err);
}