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

feature #2858: First version of VNET reservation. VNET is created, addresses allocated. Needs to set free addr methods upon reservation removal.

This commit is contained in:
Ruben S. Montero 2014-05-27 17:19:36 +02:00
parent 88987631d9
commit d5deaaf9e4
12 changed files with 596 additions and 51 deletions

View File

@ -38,6 +38,40 @@ public:
virtual ~AddressRange(){};
// *************************************************************************
// Address Range types
// *************************************************************************
/**
* Type of Addresses defined by this address range
*/
enum AddressType
{
NONE = 0x00000000, /** Undefined Address Type */
ETHER = 0x00000001, /** MAC address type */
IP4 = 0x00000003, /** IP version 4 address */
IP6 = 0x00000005, /** IP version 6 address */
IP4_6 = 0x00000007 /** IP dual stack version 4 & 6 addresses */
};
/**
* Return the string representation of an AddressType
* @param ob the type
* @return the string
*/
static string type_to_str(AddressType ob);
/**
* Return the string representation of an AddressType
* @param ob the type
* @return the string
*/
static AddressType str_to_type(string& str_type);
// *************************************************************************
// Address Range initialization functions
// *************************************************************************
/**
* Init an Address Range based on a vector attribute the following
* attributes will be parsed (* are optional):
@ -84,31 +118,9 @@ public:
*/
void to_xml(ostringstream &oss) const;
/**
* Type of Addresses defined by this address range
*/
enum AddressType
{
NONE = 0x00000000, /** Undefined Address Type */
ETHER = 0x00000001, /** MAC address type */
IP4 = 0x00000003, /** IP version 4 address */
IP6 = 0x00000005, /** IP version 6 address */
IP4_6 = 0x00000007 /** IP dual stack version 4 & 6 addresses */
};
/**
* Return the string representation of an AddressType
* @param ob the type
* @return the string
*/
static string type_to_str(AddressType ob);
/**
* Return the string representation of an AddressType
* @param ob the type
* @return the string
*/
static AddressType str_to_type(string& str_type);
// *************************************************************************
// Address allocation functions
// *************************************************************************
/**
* Returns an unused address, which becomes used and fills a NIC attribute
@ -177,6 +189,38 @@ public:
*/
int free_addr_by_ip(PoolObjectSQL::ObjectType ot, int id, const string& ip);
/**
* Frees all previous allocated address to the given object
* @param ot the object type of the owner of the address
* @param obid the id of the owner of the address
* @return the number of addresses freed
*/
int free_addr_by_owner(PoolObjectSQL::ObjectType ot, int obid);
// *************************************************************************
// Address Reservation
// *************************************************************************
/**
* Reserve a given number of addresses from this address range
* @param pvid the id of the parent VNET
* @param vid the id of the VNET making the reservation
* @param size number of addresses to reserve
* @param rar a new address range to place the reservation
* @return 0 on success
*/
int reserve_addr(int pvid, int vid, unsigned int rsize, AddressRange *rar);
/*
void reserve_addr_by_ip();
void reserve_addr_by_mac();
*/
// *************************************************************************
// Helpers
// *************************************************************************
/**
* Return the id for this address range
*/
@ -193,6 +237,14 @@ public:
return used_addr;
}
/**
* Return the number of free addresses
*/
unsigned int get_free_addr() const
{
return size - used_addr;
}
/**
* Returns the string value of an Address Range Attribute
* @param name of the attribute

View File

@ -37,6 +37,10 @@ public:
virtual ~AddressRangePool();
// *************************************************************************
// Inititalization functions
// *************************************************************************
/**
* Builds the address range set from an array of VectorAttributes. This
* function is used to create address ranges.
@ -54,6 +58,10 @@ public:
*/
int from_xml_node(const xmlNodePtr node);
// *************************************************************************
// Address Range management interface
// *************************************************************************
/**
* Removes an address range from the pool if it does not contain any used
* leases
@ -70,12 +78,14 @@ public:
void update_ar(vector<Attribute *> ars);
/**
* Generate a XML representation of the Address Range Pool
* @param sstream where the ARPool is written
* @param extended true to include lease information
* @return the string with the XML
* Allocates a new address range in the pool.
* @return the new address range added to the pool
*/
string& to_xml(string& sstream, bool extended) const;
AddressRange * allocate_ar();
// *************************************************************************
// Address allocation interface
// *************************************************************************
/**
* Allocates an address in a suitable address range from the pool
@ -182,6 +192,33 @@ public:
*/
void free_addr_by_ip(PoolObjectSQL::ObjectType ot, int id, const string& ip);
/**
* Frees all the addressed owned by the given object
* @param ot the type of the object requesting the address (VM or NET)
* @param obid the id of the object requesting the address
*/
void free_addr_by_owner(PoolObjectSQL::ObjectType ot, int obid);
// *************************************************************************
// Address reservation
// *************************************************************************
/**
* Reserve a given number of addresses from the first address range with
* enough free addresses to allocate the reservation
* @param pvid the id of the parent VNET
* @param vid the id of the VNET making the reservation
* @param size number of addresses to reserve
* @param rar a new address range to place the reservation
* @return 0 on success
*/
int reserve_addr(int pvid, int vid, unsigned int rsize, AddressRange *rar);
// *************************************************************************
// Helpers & Formatting
// *************************************************************************
/**
* Return the number of used addresses
*/
@ -198,6 +235,14 @@ public:
*/
void get_attribute(const char * name, string& value, int ar_id) const;
/**
* Generate a XML representation of the Address Range Pool
* @param sstream where the ARPool is written
* @param extended true to include lease information
* @return the string with the XML
*/
string& to_xml(string& sstream, bool extended) const;
private:
/**
* Stores the Address Ranges in a template form. This template is used

View File

@ -49,6 +49,7 @@ protected:
virtual int leases_action(VirtualNetwork * vn,
VirtualNetworkTemplate * tmpl,
RequestAttributes& att,
string& error_str) = 0;
/* -------------------------------------------------------------------- */
@ -68,6 +69,7 @@ public:
int leases_action(VirtualNetwork * vn,
VirtualNetworkTemplate * tmpl,
RequestAttributes& att,
string& error_str)
{
return vn->add_ar(tmpl, error_str);
@ -109,6 +111,7 @@ public:
int leases_action(VirtualNetwork * vn,
VirtualNetworkTemplate * tmpl,
RequestAttributes& att,
string& error_str)
{
error_str.clear();
@ -132,6 +135,7 @@ public:
int leases_action(VirtualNetwork * vn,
VirtualNetworkTemplate * tmpl,
RequestAttributes& att,
string& error_str)
{
return vn->hold_leases(tmpl, error_str);
@ -151,12 +155,34 @@ public:
int leases_action(VirtualNetwork * vn,
VirtualNetworkTemplate * tmpl,
RequestAttributes& att,
string& error_str)
{
return vn->free_leases(tmpl, error_str);
}
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class VirtualNetworkReserve: public Request
{
public:
VirtualNetworkReserve():Request("VirtualNetworkReserve", "A:sis",
"Reserve network addresses")
{
Nebula& nd = Nebula::instance();
pool = nd.get_vnpool();
auth_object = PoolObjectSQL::NET;
auth_op = AuthRequest::USE;
};
~VirtualNetworkReserve(){};
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att);
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -56,6 +56,10 @@ public:
return new VirtualNetworkTemplate;
}
// *************************************************************************
// Address Range management interface
// *************************************************************************
/**
* Add an address range to the virtual network
* @param ars_tmpl template in the form AR = [TYPE=...,IP=...,SIZE=...].
@ -72,6 +76,15 @@ public:
*/
int rm_ar(unsigned int ar_id, string& error_msg);
/**
* Allocates a new (and empty) address range to the AR pool
* @return pointer to the ar added to the AR pool
*/
AddressRange * allocate_ar()
{
return ar_pool.allocate_ar();
}
/**
* Update an address range to the virtual network
* @param ars_tmpl template in the form AR = [AR_ID=...]. The address range
@ -79,6 +92,10 @@ public:
*/
void update_ar(VirtualNetworkTemplate * ars_tmpl);
// *************************************************************************
// Address hold/release interface
// *************************************************************************
/**
* Holds a Lease, marking it as used
* @param leases template in the form LEASES = [IP=XX].
@ -98,6 +115,10 @@ public:
*/
int free_leases(VirtualNetworkTemplate* leases, string& error_msg);
// *************************************************************************
// Address allocation funtions
// *************************************************************************
/**
* Gets a new address lease for a specific VM
* @param vid VM identifier
@ -144,13 +165,51 @@ public:
* @param arid of the address range where the address was leased from
* @param vid the ID of the VM
* @param mac MAC address identifying the lease
* @return 0 if success
*/
void free_addr(unsigned int arid, int vid, const string& mac)
{
ar_pool.free_addr(arid, PoolObjectSQL::VM, vid, mac);
}
/**
* Release all previously given address leases to the given object
* @param ot the type of the object requesting the address (VM or NET)
* @param obid the id of the object requesting the address
*/
void free_addr_by_owner(PoolObjectSQL::ObjectType ot, int obid)
{
ar_pool.free_addr_by_owner(ot, obid);
}
/**
* Modifies the given nic attribute adding the following attributes:
* * IP: leased from network
* * MAC: leased from network
* * BRIDGE: for this virtual network
* @param nic attribute for the VM template
* @param vid of the VM getting the lease
* @param inherit_attrs Attributes to be inherited from the vnet template
* into the nic
* @return 0 on success
*/
int nic_attribute(
VectorAttribute * nic,
int vid,
const vector<string>& inherit_attrs);
// *************************************************************************
// Network Reservation functions
// *************************************************************************
int reserve_addr(VirtualNetwork *rvnet, unsigned int rsize, string& error_str);
// *************************************************************************
// Formatting & Helper functions
// *************************************************************************
/**
* Gets used leases
* @return number of network leases in used
@ -185,22 +244,6 @@ public:
*/
string& to_xml_extended(string& xml) const;
/**
* Modifies the given nic attribute adding the following attributes:
* * IP: leased from network
* * MAC: leased from network
* * BRIDGE: for this virtual network
* @param nic attribute for the VM template
* @param vid of the VM getting the lease
* @param inherit_attrs Attributes to be inherited from the vnet template
* into the nic
* @return 0 on success
*/
int nic_attribute(
VectorAttribute * nic,
int vid,
const vector<string>& inherit_attrs);
/**
* Replace the template of the virtual network it also updates the BRIDGE,
* PHY_DEV, VLAN_ID and VLAN attributes.
@ -219,6 +262,15 @@ public:
*/
void get_template_attribute(const char * name, string& value, int ar_id) const;
/**
* @return A copy of the VNET Template
*/
VirtualNetworkTemplate * clone_template() const
{
return new VirtualNetworkTemplate(
*(static_cast<VirtualNetworkTemplate *>(obj_template)));
};
private:
// -------------------------------------------------------------------------

View File

@ -66,6 +66,22 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper
:description => "IP6 ula prefix"
}
R_NAME = {
:name => "rname",
:short => "-n reservation name",
:large => "--name reservation name",
:format => String,
:description => "Name of the address reservation"
}
R_SIZE = {
:name => "rsize",
:short => "-s reservation size",
:large => "--size reservation size",
:format => String,
:description => "Number of addresses to reserve"
}
def self.rname
"VNET"
end
@ -240,7 +256,7 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper
if d['VM']
"VM : #{d['VM']}"
elsif d['VNET']
"NET: #{d['VM']}"
"NET: #{d['VNET']}"
end
end

View File

@ -182,6 +182,33 @@ cmd=CommandParser::CmdParser.new(ARGV) do
end
end
reserve_desc = <<-EOT.unindent
Reserve addresses from the Virtual Network
EOT
command :reserve, reserve_desc, :vnetid,
:options=>STD_OPTIONS + [OneVNetHelper::AR, OneVNetHelper::R_NAME,
OneVNetHelper::R_SIZE] do
helper.perform_action(args[0],options,"reservation made") do |vn|
ar = options[:ar_id] || -1
rsize = options[:rsize] || -1
rname = options[:rname] || -1
if rsize == -1
STDERR.puts "Specify a size (-s size) for the reservation"
exit -1
end
if rname == -1
STDERR.puts "Specify a name (-n name) for the reservation"
exit -1
end
vn.reserve(rname, rsize)
end
end
chgrp_desc = <<-EOT.unindent
Changes the Virtual Network group
EOT

View File

@ -35,7 +35,8 @@ module OpenNebula
:update => "vn.update",
:hold => "vn.hold",
:release => "vn.release",
:rename => "vn.rename"
:rename => "vn.rename",
:reserve => "vn.reserve"
}
# Creates a VirtualNetwork description with just its identifier
@ -185,6 +186,21 @@ module OpenNebula
return rc
end
# Reserve a set of addresses from this virtual network
# @param name [String] of the reservation
# @param rsize[String] number of addresses to reserve
def reserve(rname, rsize)
return Error.new('ID not defined') if !@pe_id
rtmpl = "NAME = #{rname}\n"
rtmpl << "SIZE = #{rsize}\n"
rc = @client.call(VN_METHODS[:reserve], @pe_id, rtmpl)
rc = nil if !OpenNebula.is_error?(rc)
return rc
end
# Changes the owner/group
#
# @param uid [Integer] the new owner id. Set to -1 to leave the current one

View File

@ -281,6 +281,7 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr vn_update_ar(new VirtualNetworkUpdateAddressRange());
xmlrpc_c::methodPtr vn_hold(new VirtualNetworkHold());
xmlrpc_c::methodPtr vn_release(new VirtualNetworkRelease());
xmlrpc_c::methodPtr vn_reserve(new VirtualNetworkReserve());
// Update Template Methods
xmlrpc_c::methodPtr image_update(new ImageUpdateTemplate());
@ -486,6 +487,7 @@ void RequestManager::register_xml_methods()
RequestManagerRegistry.addMethod("one.groupquota.update", group_set_default_quota);
/* Network related methods*/
RequestManagerRegistry.addMethod("one.vn.reserve", vn_reserve);
RequestManagerRegistry.addMethod("one.vn.add_ar", vn_add_ar);
RequestManagerRegistry.addMethod("one.vn.rm_ar", vn_rm_ar);
RequestManagerRegistry.addMethod("one.vn.update_ar", vn_update_ar);

View File

@ -64,7 +64,7 @@ void RequestManagerVirtualNetwork::
return;
}
rc = leases_action(vn,&tmpl,error_str);
rc = leases_action(vn, &tmpl, att, error_str);
if ( rc < 0 )
{
@ -127,3 +127,145 @@ void VirtualNetworkRmAddressRange::
success_response(id, att);
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
void VirtualNetworkReserve::request_execute(
xmlrpc_c::paramList const& paramList, RequestAttributes& att)
{
int id = xmlrpc_c::value_int (paramList.getInt(1));
string str_tmpl = xmlrpc_c::value_string (paramList.getString(2));
VirtualNetworkTemplate tmpl;
VirtualNetwork * vn;
string error_str;
int rc;
if ( basic_authorization(id, att) == false )
{
return;
}
// ----------------- Process the Reservation Template -------------------
rc = tmpl.parse_str_or_xml(str_tmpl, error_str);
if ( rc != 0 )
{
failure_response(ACTION,
request_error("Error in reservation request", error_str), att);
return;
}
int size;
if ( !tmpl.get("SIZE", size) || size <= 0 )
{
failure_response(ACTION, request_error("Error in reservation request",
"Reservation SIZE must be a greater than 0"), att);
return;
}
string name;
tmpl.get("NAME", name);
if (name.empty())
{
failure_response(ACTION, request_error("Error in reservation request",
"NAME for reservation has to be set"), att);
return;
}
// --------------- Create a new VNET to place the reservation -------------
vn = static_cast<VirtualNetwork *>(pool->get(id,true));
if ( vn == 0 )
{
failure_response(NO_EXISTS, get_error(object_name(auth_object),id),att);
return;
}
VirtualNetworkTemplate * vtmpl = vn->clone_template();
vtmpl->replace("NAME", name);
int rid;
int cluster_id = vn->get_cluster_id();
rc = (static_cast<VirtualNetworkPool *>(pool))->allocate(att.uid, att.gid,
att.uname, att.gname, att.umask, vtmpl, &rid, cluster_id,
vn->get_cluster_name(), error_str);
if (rc < 0)
{
failure_response(INTERNAL,
request_error("Cannot allocate reservation VNET", error_str), att);
vn->unlock();
return;
}
VirtualNetwork * rvn = static_cast<VirtualNetwork *>(pool->get(rid,true));
if (rvn == 0)
{
failure_response(INTERNAL,
request_error("Cannot allocate reservation VNET",""), att);
vn->unlock();
return;
}
// -------------- Make address reservation and set it ----------------------
if (vn->reserve_addr(rvn, size, error_str) != 0 )
{
failure_response(ACTION, request_error(error_str,""), att);
pool->drop(rvn, error_str);
rvn->unlock();
vn->unlock();
return;
}
pool->update(rvn);
pool->update(vn);
rvn->unlock();
vn->unlock();
// -------------- Add the reservation to the cluster ----------------------
if ( cluster_id != ClusterPool::NONE_CLUSTER_ID )
{
Nebula& nd = Nebula::instance();
ClusterPool * clpool = nd.get_clpool();
Cluster * cluster = clpool->get(cluster_id, true);
if ( cluster != 0 )
{
cluster->add_vnet(rid, error_str);
clpool->update(cluster);
cluster->unlock();
}
}
success_response(rid, att);
}

View File

@ -178,6 +178,16 @@ int AddressRange::from_vattr(VectorAttribute *vattr, string& error_msg)
vattr->replace("AR_ID", id);
vattr->remove("ALLOCATED");
vattr->remove("USED_LEASES");
vattr->remove("LEASES");
vattr->remove("PARENT_NETWORK_AR_ID");
vattr->remove("PARENT_NETWORK");
if (do_mac) //Need to add MAC to the attribute
{
set_mac(0, attr);
@ -214,6 +224,10 @@ void AddressRange::update_attributes(VectorAttribute *vup)
vup->remove("LEASES");
vup->remove("PARENT_NETWORK_AR_ID");
vup->remove("PARENT_NETWORK");
/* ----------------- update known attributes ----------------- */
unsigned int new_size;
@ -905,6 +919,38 @@ int AddressRange::free_addr_by_ip(PoolObjectSQL::ObjectType ot, int obid,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int AddressRange::free_addr_by_owner(PoolObjectSQL::ObjectType ot, int obid)
{
map<unsigned int, long long>::iterator it = allocated.begin();
long long obj_pack = ot | (obid & 0x00000000FFFFFFFFLL);
int freed = 0;
while (it != allocated.end())
{
if (it->second == obj_pack)
{
map<unsigned int, long long>::iterator prev_it = it++;
allocated.erase(prev_it);
used_addr--;
freed++;
}
else
{
it++;
}
}
return freed;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int AddressRange::hold_by_ip(const string& ip_s)
{
if (!(type & 0x00000002))//Not of type IP4 or IP4_6
@ -965,6 +1011,63 @@ int AddressRange::hold_by_mac(const string& mac_s)
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int AddressRange::reserve_addr(int pvid, int vid, unsigned int rsize,
AddressRange *rar)
{
bool isset = false;
unsigned int first_index;
int pnet;
if (rsize > (size - used_addr))
{
return -1; //reservation dosen't fit
}
if ((attr->vector_value("PARENT_NETWORK_ID", pnet) == 0 ) && (pnet > -1))
{
return -1; //This address range is already a reservation
}
for ( unsigned int i=0; i<rsize; next = (next+1)%size )
{
if ( allocated.count(next) == 0 )
{
allocate_addr(PoolObjectSQL::NET, vid, next);
if (!isset)
{
first_index = next;
isset = true;
}
i++;
}
}
VectorAttribute * new_ar = attr->clone();
string errmsg;
set_mac(first_index, new_ar);
if (type & 0x00000002 )
{
set_ip(first_index, new_ar);
}
new_ar->replace("SIZE",rsize);
rar->from_vattr(new_ar, errmsg);
new_ar->replace("PARENT_NETWORK_ID", pvid);
new_ar->replace("PARENT_NETWORK_AR_ID",id);
return 0;
}
/* ************************************************************************** */
/* ************************************************************************** */

View File

@ -74,6 +74,18 @@ int AddressRangePool::from_vattr(vector<Attribute *> ars, string& error_msg)
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
AddressRange * AddressRangePool::allocate_ar()
{
AddressRange * ar = new AddressRange(next_ar);
ar_pool.insert(make_pair(next_ar++, ar));
return ar;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void AddressRangePool::update_ar(vector<Attribute *> ars)
{
vector<Attribute *>::iterator it;
@ -175,6 +187,7 @@ int AddressRangePool::rm_ar(unsigned int ar_id, string& error_msg)
vector<Attribute*> ars;
vector<Attribute*>::iterator it_ar;
Attribute * the_ar = 0;
unsigned int ar_id_templ;
@ -369,6 +382,19 @@ void AddressRangePool::free_addr_by_ip(PoolObjectSQL::ObjectType ot, int obid,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void AddressRangePool::free_addr_by_owner(PoolObjectSQL::ObjectType ot, int oid)
{
map<unsigned int, AddressRange *>::iterator it;
for (it=ar_pool.begin(); it!=ar_pool.end(); it++)
{
used_addr = used_addr - it->second->free_addr_by_owner(ot, oid);
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void AddressRangePool::get_attribute(const char * name, string& value,
int ar_id) const
{
@ -471,3 +497,23 @@ int AddressRangePool::hold_by_mac(const string& mac_s)
return rc;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int AddressRangePool::reserve_addr(int pvid, int vid, unsigned int rsize,
AddressRange *rar)
{
map<unsigned int, AddressRange *>::iterator it;
for (it=ar_pool.begin(); it!=ar_pool.end(); it++)
{
if ((it->second->get_free_addr() >= rsize) &&
(it->second->reserve_addr(pvid, vid, rsize, rar) == 0))
{
used_addr += rsize;
return 0;
}
}
return -1;
}

View File

@ -766,3 +766,21 @@ void VirtualNetwork::get_template_attribute(const char * name, string& value, in
PoolObjectSQL::get_template_attribute(name, value);
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualNetwork::reserve_addr(VirtualNetwork *rvnet,
unsigned int rsize, string& error_str)
{
AddressRange *rar = rvnet->allocate_ar();
if (ar_pool.reserve_addr(oid, rvnet->get_oid(), rsize, rar) != 0)
{
error_str = "Not enough free addresses in an address range";
return -1;
}
return 0;
}