diff --git a/include/FixedLeases.h b/include/FixedLeases.h index 399afb02d7..d194a8130c 100644 --- a/include/FixedLeases.h +++ b/include/FixedLeases.h @@ -44,8 +44,7 @@ public: FixedLeases(SqlDB * db, int _oid, unsigned int _mac_prefix): - Leases(db,_oid,0), - mac_prefix(_mac_prefix), + Leases(db,_oid,0,_mac_prefix), current(leases.begin()){}; ~FixedLeases(){}; @@ -112,11 +111,6 @@ public: private: - /** - * The default MAC prefix for the Leases - */ - unsigned int mac_prefix; - /** * Current lease pointer */ diff --git a/include/Leases.h b/include/Leases.h index ef38c2c13b..74a04d7928 100644 --- a/include/Leases.h +++ b/include/Leases.h @@ -40,9 +40,9 @@ public: * @param _oid the virtual network unique identifier * @param _size the max number of leases */ - Leases(SqlDB * _db, int _oid, unsigned long _size): + Leases(SqlDB * _db, int _oid, unsigned long _size, unsigned int _mac_prefix): ObjectSQL(), - oid(_oid), size(_size), n_used(0), db(_db){}; + oid(_oid), size(_size), n_used(0), mac_prefix(_mac_prefix), db(_db){}; virtual ~Leases() { @@ -102,6 +102,26 @@ public: virtual int remove_leases(vector& vector_leases, string& error_msg) = 0; + /** + * Holds a Lease, marking it as used + * @param vector_leases vector of VectorAttribute objects. For the + * moment, the vector can only contain one LEASE. + * @param error_msg If the action fails, this message contains + * the reason. + * @return 0 on success + */ + int hold_leases(vector& vector_leases, string& error_msg); + + /** + * Releases a Lease on hold + * @param vector_leases vector of VectorAttribute objects. For the + * moment, the vector can only contain one LEASE. + * @param error_msg If the action fails, this message contains + * the reason. + * @return 0 on success + */ + int free_leases(vector& vector_leases, string& error_msg); + // ------------------------------------------------------------------------- // ------------------------------------------------------------------------- @@ -230,13 +250,13 @@ protected: // Leases fields // ------------------------------------------------------------------------- /** - * Leases indentifier. Connects it to a Virtual Network - */ + * Leases identifier. Connects it to a Virtual Network + */ int oid; /** - * Number of possible leases (free + asigned) - */ + * Number of possible leases (free + assigned) + */ unsigned int size; /** @@ -249,6 +269,11 @@ protected: */ int n_used; + /** + * The default MAC prefix for the Leases + */ + unsigned int mac_prefix; + // ------------------------------------------------------------------------- // DataBase implementation variables // ------------------------------------------------------------------------- @@ -286,11 +311,11 @@ protected: friend ostream& operator<<(ostream& os, Lease& _lease); /** - * Function to print the Leases object into a string in - * XML format - * @param xml the resulting XML string - * @return a reference to the generated string - */ + * Function to print the Leases object into a string in + * XML format + * @param xml the resulting XML string + * @return a reference to the generated string + */ string& to_xml(string& xml) const; private: diff --git a/include/RangedLeases.h b/include/RangedLeases.h index 946db6f349..a8a81d9968 100644 --- a/include/RangedLeases.h +++ b/include/RangedLeases.h @@ -18,6 +18,7 @@ #define RANGED_LEASES_H_ #include "Leases.h" +#include "VirtualNetwork.h" using namespace std; @@ -30,12 +31,23 @@ public: // ************************************************************************* RangedLeases(SqlDB * db, int _oid, - unsigned long _size, unsigned int _mac_prefix, - const string& _network_address); + unsigned int _ip_start, + unsigned int _ip_end); ~RangedLeases(){}; + /** + * Reads (and clears) the necessary attributes to define a Ranged VNet + * @param vn Virtual Network + * @param ip_start First IP of the range + * @param ip_end Last IP of the range + * @param error_str Error reason, if any + * @return 0 on success, -1 otherwise + */ + static int process_template(VirtualNetwork * vn, + unsigned int& ip_start, unsigned int& ip_end, string& error_str); + /** * Returns an unused lease, which becomes used * @param vid identifier of the VM getting this lease @@ -105,15 +117,9 @@ public: } private: - /** - * The default MAC prefix for the Leases - */ - unsigned int mac_prefix; - /** - * The Network address to generate leases - */ - unsigned int network_address; + unsigned int ip_start; + unsigned int ip_end; unsigned int current; diff --git a/include/RequestManagerVirtualNetwork.h b/include/RequestManagerVirtualNetwork.h index f402499ac2..4a6245754b 100644 --- a/include/RequestManagerVirtualNetwork.h +++ b/include/RequestManagerVirtualNetwork.h @@ -93,6 +93,44 @@ public: } }; +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VirtualNetworkHold : public RequestManagerVirtualNetwork +{ +public: + VirtualNetworkHold(): + RequestManagerVirtualNetwork("VirtualNetworkHold", + "Holds a virtual network Lease as used"){}; + ~VirtualNetworkHold(){}; + + int leases_action(VirtualNetwork * vn, + VirtualNetworkTemplate * tmpl, + string& error_str) + { + return vn->hold_leases(tmpl, error_str); + } +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VirtualNetworkRelease : public RequestManagerVirtualNetwork +{ +public: + VirtualNetworkRelease(): + RequestManagerVirtualNetwork("VirtualNetworkRelease", + "Releases a virtual network Lease on hold"){}; + ~VirtualNetworkRelease(){}; + + int leases_action(VirtualNetwork * vn, + VirtualNetworkTemplate * tmpl, + string& error_str) + { + return vn->free_leases(tmpl, error_str); + } +}; + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/include/VirtualNetwork.h b/include/VirtualNetwork.h index b398b8aee2..cca301be12 100644 --- a/include/VirtualNetwork.h +++ b/include/VirtualNetwork.h @@ -85,7 +85,7 @@ public: /** * Adds Leases to the virtual network (Only implemented for FIXED networks) - * @param leases_template template in the form LEASES = [IP=XX, MAC=XX]. + * @param leases template in the form LEASES = [IP=XX, MAC=XX]. * MAC is optional. The template can only contain one LEASE * definition. * @param error_msg If the action fails, this message contains the reason. @@ -96,7 +96,7 @@ public: /** * Removes Leases from the virtual network; if they are not used.(Only * implemented for FIXED networks) - * @param leases_template template in the form LEASES = [IP=XX]. + * @param leases template in the form LEASES = [IP=XX]. * The template can only contain one LEASE definition. * @param error_msg If the action fails, this message contains * the reason. @@ -104,6 +104,25 @@ public: */ int remove_leases(VirtualNetworkTemplate* leases, string& error_msg); + /** + * Holds a Lease, marking it as used + * @param leases template in the form LEASES = [IP=XX]. + * The template can only contain one LEASE definition. + * @param error_msg If the action fails, this message contains the reason. + * @return 0 on success + */ + int hold_leases(VirtualNetworkTemplate * leases, string& error_msg); + + /** + * Releases a Lease on hold + * @param leases template in the form LEASES = [IP=XX]. + * The template can only contain one LEASE definition. + * @param error_msg If the action fails, this message contains + * the reason. + * @return 0 on success + */ + int free_leases(VirtualNetworkTemplate* leases, string& error_msg); + /** * Gets a new lease for a specific VM * @param vid VM identifier @@ -227,6 +246,9 @@ private: */ Leases * leases; + unsigned int ip_start; + unsigned int ip_end; + // ************************************************************************* // DataBase implementation (Private) // ************************************************************************* diff --git a/src/cli/one_helper/onevnet_helper.rb b/src/cli/one_helper/onevnet_helper.rb index 7216ad6abb..e672d884b5 100644 --- a/src/cli/one_helper/onevnet_helper.rb +++ b/src/cli/one_helper/onevnet_helper.rb @@ -69,13 +69,26 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper puts vn.template_str(false) - leases_str = vn.template_like_str('/VNET/LEASES', false) - - if !leases_str.empty? + if vn.type_str == "RANGED" puts - CLIHelper.print_header(str_h1 % ["LEASES INFORMATION"], false) - puts leases_str + CLIHelper.print_header(str_h1 % ["RANGE"], false) + puts str % ["IP_START", vn['RANGE/IP_START']] + puts str % ["IP_END", vn['RANGE/IP_END']] end + + lease_types = [ ["LEASES ON HOLD", 'LEASE[USED=1 and VID=-1]'], + ["USED LEASES", 'LEASE[USED=1 and VID>-1]'], + ["FREE LEASES", 'LEASE[USED=0]'] ] + + lease_types.each { |pair| + leases_str = vn.template_like_str('/VNET/LEASES', false, pair[1]) + + if !leases_str.empty? + puts + CLIHelper.print_header(str_h1 % [pair[0]], false) + puts leases_str + end + } end def format_pool(options) diff --git a/src/cli/onevnet b/src/cli/onevnet index b5101c05a6..91a648c97c 100755 --- a/src/cli/onevnet +++ b/src/cli/onevnet @@ -93,8 +93,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do Adds a lease to the Virtual Network EOT - command :addleases, 'Adds a lease to the Virtual Network', :vnetid, :ip, - [:mac, nil] do + command :addleases, addleases_desc, :vnetid, :ip, [:mac, nil] do helper.perform_action(args[0],options,"lease added") do |vn| vn.addleases(args[1], args[2]) end @@ -110,6 +109,26 @@ cmd=CommandParser::CmdParser.new(ARGV) do end end + hold_desc = <<-EOT.unindent + Holds a Virtual Network lease, marking it as used + EOT + + command :hold, hold_desc, :vnetid, :ip do + helper.perform_action(args[0],options,"lease on hold") do |vn| + vn.hold(args[1]) + end + end + + release_desc = <<-EOT.unindent + Releases a Virtual Network lease on hold + EOT + + command :release, release_desc, :vnetid, :ip do + helper.perform_action(args[0],options,"lease released") do |vn| + vn.release(args[1]) + end + end + publish_desc = <<-EOT.unindent Publishes the given Virtual Network. A public Virtual Network can be seen and used by other Users in the Virtual Network's group diff --git a/src/oca/java/src/org/opennebula/client/vnet/VirtualNetwork.java b/src/oca/java/src/org/opennebula/client/vnet/VirtualNetwork.java index ac58d7a316..9bd60df8d3 100644 --- a/src/oca/java/src/org/opennebula/client/vnet/VirtualNetwork.java +++ b/src/oca/java/src/org/opennebula/client/vnet/VirtualNetwork.java @@ -36,7 +36,8 @@ public class VirtualNetwork extends PoolElement{ private static final String RMLEASES = METHOD_PREFIX + "rmleases"; private static final String CHOWN = METHOD_PREFIX + "chown"; private static final String UPDATE = METHOD_PREFIX + "update"; - + private static final String HOLD = METHOD_PREFIX + "hold"; + private static final String RELEASE = METHOD_PREFIX + "release"; /** * Creates a new virtual network representation. @@ -140,6 +141,32 @@ public class VirtualNetwork extends PoolElement{ return client.call(RMLEASES, id, template); } + /** + * Holds a VirtualNetwork lease, marking it as used + * + * @param client XML-RPC Client. + * @param id The virtual network id (nid) of the target network. + * @param template IP to hold, e.g. "LEASES = [ IP = 192.168.0.5 ]" + * @return A encapsulated response. + */ + public static OneResponse hold(Client client, int id, String template) + { + return client.call(HOLD, id, template); + } + + /** + * Releases a VirtualNetwork lease on hold + * + * @param client XML-RPC Client. + * @param id The virtual network id (nid) of the target network. + * @param template IP to release, e.g. "LEASES = [ IP = 192.168.0.5 ]" + * @return A encapsulated response. + */ + public static OneResponse release(Client client, int id, String template) + { + return client.call(RELEASE, id, template); + } + /** * Changes the owner/group * @@ -271,6 +298,30 @@ public class VirtualNetwork extends PoolElement{ return rmLeases(client, id, lease_template); } + /** + * Holds a VirtualNetwork lease, marking it as used + * + * @param ip IP to hold, e.g. "192.168.0.5" + * @return A encapsulated response. + */ + public OneResponse hold(String ip) + { + String lease_template = "LEASES = [ IP = " + ip + " ]"; + return hold(client, id, lease_template); + } + + /** + * Releases a VirtualNetwork lease on hold + * + * @param ip IP to release, e.g. "192.168.0.5" + * @return A encapsulated response. + */ + public OneResponse release(String ip) + { + String lease_template = "LEASES = [ IP = " + ip + " ]"; + return release(client, id, lease_template); + } + /** * Changes the owner/group * diff --git a/src/oca/java/test/VirtualNetworkTest.java b/src/oca/java/test/VirtualNetworkTest.java index dcea0775e6..6a0c86537b 100644 --- a/src/oca/java/test/VirtualNetworkTest.java +++ b/src/oca/java/test/VirtualNetworkTest.java @@ -209,6 +209,54 @@ public class VirtualNetworkTest fixed_vnet.delete(); } + @Test + public void holdFixed() + { + res = VirtualNetwork.allocate(client, fixed_template); + assertTrue( !res.isError() ); + + VirtualNetwork fixed_vnet = + new VirtualNetwork(Integer.parseInt(res.getMessage()), client); + + res = fixed_vnet.hold("130.10.0.1"); + assertTrue( !res.isError() ); + + res = fixed_vnet.hold("130.10.0.5"); + assertTrue( res.isError() ); + + res = fixed_vnet.release("130.10.0.1"); + assertTrue( !res.isError() ); + + res = fixed_vnet.release("130.10.0.1"); + assertTrue( res.isError() ); + + res = fixed_vnet.release("130.10.0.5"); + assertTrue( res.isError() ); + + fixed_vnet.delete(); + } + + @Test + public void holdRanged() + { + res = vnet.hold("192.168.0.10"); + assertTrue( !res.isError() ); + + res = vnet.hold("192.168.100.1"); + assertTrue( res.isError() ); + + res = vnet.release("192.168.0.10"); + assertTrue( !res.isError() ); + + res = vnet.release("192.168.0.10"); + assertTrue( res.isError() ); + + res = vnet.release("192.168.100.1"); + assertTrue( res.isError() ); + + vnet.delete(); + } + @Test public void update() { diff --git a/src/oca/ruby/OpenNebula/VirtualNetwork.rb b/src/oca/ruby/OpenNebula/VirtualNetwork.rb index 7020bac0fc..b932d7cbe8 100644 --- a/src/oca/ruby/OpenNebula/VirtualNetwork.rb +++ b/src/oca/ruby/OpenNebula/VirtualNetwork.rb @@ -32,7 +32,9 @@ module OpenNebula :addleases => "vn.addleases", :rmleases => "vn.rmleases", :chown => "vn.chown", - :update => "vn.update" + :update => "vn.update", + :hold => "vn.hold", + :release => "vn.release" } VN_TYPES=%w{RANGED FIXED} @@ -128,6 +130,32 @@ module OpenNebula return rc end + # Holds a virtual network Lease as used + # @param ip [String] IP to hold + def hold(ip) + return Error.new('ID not defined') if !@pe_id + + lease_template = "LEASES = [ IP = #{ip} ]" + + rc = @client.call(VN_METHODS[:hold], @pe_id, lease_template) + rc = nil if !OpenNebula.is_error?(rc) + + return rc + end + + # Releases a virtual network Lease on hold + # @param ip [String] IP to release + def release(ip) + return Error.new('ID not defined') if !@pe_id + + lease_template = "LEASES = [ IP = #{ip} ]" + + rc = @client.call(VN_METHODS[:release], @pe_id, lease_template) + rc = nil if !OpenNebula.is_error?(rc) + + return rc + end + # Changes the owner/group # uid:: _Integer_ the new owner id. Set to -1 to leave the current one # gid:: _Integer_ the new group id. Set to -1 to leave the current one diff --git a/src/oca/ruby/OpenNebula/XMLUtils.rb b/src/oca/ruby/OpenNebula/XMLUtils.rb index 1dfa884532..3505fb9cc6 100644 --- a/src/oca/ruby/OpenNebula/XMLUtils.rb +++ b/src/oca/ruby/OpenNebula/XMLUtils.rb @@ -201,7 +201,7 @@ module OpenNebula template_like_str('TEMPLATE', indent) end - def template_like_str(root_element, indent=true) + def template_like_str(root_element, indent=true, xpath_exp=nil) if NOKOGIRI xml_template=@xml.xpath(root_element).to_s rexml=REXML::Document.new(xml_template).root @@ -217,7 +217,7 @@ module OpenNebula ind_tab=' ' end - str=rexml.collect {|n| + str=rexml.elements.collect(xpath_exp) {|n| if n.class==REXML::Element str_line="" if n.has_elements? diff --git a/src/rm/RequestManager.cc b/src/rm/RequestManager.cc index 6c3ca96d3e..08dd938794 100644 --- a/src/rm/RequestManager.cc +++ b/src/rm/RequestManager.cc @@ -246,6 +246,8 @@ void RequestManager::register_xml_methods() // VirtualNetwork Methods xmlrpc_c::methodPtr vn_addleases(new VirtualNetworkAddLeases()); xmlrpc_c::methodPtr vn_rmleases(new VirtualNetworkRemoveLeases()); + xmlrpc_c::methodPtr vn_hold(new VirtualNetworkHold()); + xmlrpc_c::methodPtr vn_release(new VirtualNetworkRelease()); // Update Template Methods xmlrpc_c::methodPtr image_update(new ImageUpdateTemplate()); @@ -357,6 +359,8 @@ void RequestManager::register_xml_methods() /* Network related methods*/ RequestManagerRegistry.addMethod("one.vn.addleases", vn_addleases); RequestManagerRegistry.addMethod("one.vn.rmleases", vn_rmleases); + RequestManagerRegistry.addMethod("one.vn.hold", vn_hold); + RequestManagerRegistry.addMethod("one.vn.release", vn_release); RequestManagerRegistry.addMethod("one.vn.allocate", vn_allocate); RequestManagerRegistry.addMethod("one.vn.publish", vn_publish); RequestManagerRegistry.addMethod("one.vn.update", vn_update); diff --git a/src/rm/RequestManagerVirtualNetwork.cc b/src/rm/RequestManagerVirtualNetwork.cc index af410a025f..b3bb5ed0b8 100644 --- a/src/rm/RequestManagerVirtualNetwork.cc +++ b/src/rm/RequestManagerVirtualNetwork.cc @@ -80,7 +80,7 @@ void RequestManagerVirtualNetwork:: if ( rc < 0 ) { failure_response(INTERNAL, - request_error("Error modifiying network leases",error_str), + request_error("Error modifying network leases",error_str), att); vn->unlock(); diff --git a/src/vnm/FixedLeases.cc b/src/vnm/FixedLeases.cc index abfd653ef9..02a91462c2 100644 --- a/src/vnm/FixedLeases.cc +++ b/src/vnm/FixedLeases.cc @@ -25,7 +25,7 @@ FixedLeases::FixedLeases( int _oid, unsigned int _mac_prefix, vector& vector_leases): - Leases(db,_oid,0),mac_prefix(_mac_prefix),current(leases.begin()) + Leases(db,_oid,0,_mac_prefix),current(leases.begin()) { const VectorAttribute * single_attr_lease; string _mac; diff --git a/src/vnm/Leases.cc b/src/vnm/Leases.cc index 12de451987..432e3d099e 100644 --- a/src/vnm/Leases.cc +++ b/src/vnm/Leases.cc @@ -66,6 +66,11 @@ int Leases::Lease::ip_to_number(const string& _ip, unsigned int& i_ip) { iss >> dec >> tmp >> ws; + if ( tmp > 255 ) + { + return -1; + } + i_ip <<= 8; i_ip += tmp; } @@ -381,23 +386,11 @@ int Leases::update(SqlDB * db) bool Leases::check(const string& ip) { - map::iterator it; - unsigned int _ip; Leases::Lease::ip_to_number(ip,_ip); - - it=leases.find(_ip); - - if (it!=leases.end()) - { - return it->second->used; - } - else - { - return false; - } + return check(_ip); } /* -------------------------------------------------------------------------- */ @@ -419,6 +412,95 @@ bool Leases::check(unsigned int ip) } } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int Leases::hold_leases(vector& vector_leases, + string& error_msg) +{ + const VectorAttribute * single_attr_lease = 0; + + int rc; + string ip; + string mac; + + if ( vector_leases.size() > 0 ) + { + single_attr_lease = + dynamic_cast(vector_leases[0]); + } + + if ( single_attr_lease == 0 ) + { + error_msg = "Empty lease description."; + return -1; + } + + ip = single_attr_lease->vector_value("IP"); + + if ( check(ip) ) + { + error_msg = "Lease is in use."; + return -1; + } + + rc = set(-1, ip, mac); + + if ( rc != 0 ) + { + error_msg = "Lease is not part of the NET."; + return -1; + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int Leases::free_leases(vector& vector_leases, + string& error_msg) +{ + const VectorAttribute * single_attr_lease = 0; + map::iterator it; + + unsigned int i_ip; + string st_ip; + string mac; + + if ( vector_leases.size() > 0 ) + { + single_attr_lease = + dynamic_cast(vector_leases[0]); + } + + if ( single_attr_lease == 0 ) + { + error_msg = "Empty lease description."; + return -1; + } + + st_ip = single_attr_lease->vector_value("IP"); + + if ( Leases::Lease::ip_to_number(st_ip,i_ip) != 0 ) + { + error_msg = "Wrong Lease format."; + return -1; + } + + it = leases.find(i_ip); + + if ( it == leases.end() || !it->second->used || it->second->vid != -1 ) + { + error_msg = "Lease is not on hold."; + return -1; + } + + release(st_ip); + + return 0; +} + /* ************************************************************************** */ /* Leases :: Misc */ /* ************************************************************************** */ diff --git a/src/vnm/RangedLeases.cc b/src/vnm/RangedLeases.cc index d74f599e17..0eea558afb 100644 --- a/src/vnm/RangedLeases.cc +++ b/src/vnm/RangedLeases.cc @@ -17,6 +17,7 @@ #include "RangedLeases.h" #include "Nebula.h" + #include /* ************************************************************************** */ @@ -26,35 +27,269 @@ RangedLeases::RangedLeases( SqlDB * db, int _oid, - unsigned long _size, unsigned int _mac_prefix, - const string& _network_address): - Leases(db,_oid,_size),mac_prefix(_mac_prefix),current(0) + unsigned int _ip_start, + unsigned int _ip_end): + Leases(db,_oid,0,_mac_prefix), + ip_start(_ip_start),ip_end(_ip_end),current(0) { - unsigned int net_addr; - - Leases::Lease::ip_to_number(_network_address,net_addr); - - //size is the number of hosts in the network - size = _size + 2; - - network_address = 0xFFFFFFFF << (int) ceil(log(size)/log(2)); - - network_address &= net_addr; + size = ip_end - ip_start + 1; } /* ************************************************************************** */ /* Ranged Leases :: Methods */ /* ************************************************************************** */ +int RangedLeases::process_template(VirtualNetwork* vn, + unsigned int& ip_start, unsigned int& ip_end, string& error_str) +{ + ostringstream oss; + + string st_size = ""; + string st_addr = ""; + string st_mask = ""; + + string st_ip_start = ""; + string st_ip_end = ""; + + unsigned int host_bits; + unsigned int network_bits; + + unsigned int net_addr; + unsigned int net_mask; + size_t pos; + + ip_start = 0; + ip_end = 0; + + // retrieve specific information from template + vn->erase_template_attribute("IP_START", st_ip_start); + vn->erase_template_attribute("IP_END", st_ip_end); + + if ( !st_ip_start.empty() ) + { + if ( Leases::Lease::ip_to_number(st_ip_start, ip_start) != 0 ) + { + goto error_ip_start; + } + } + + if ( !st_ip_end.empty() ) + { + if ( Leases::Lease::ip_to_number(st_ip_end, ip_end) != 0 ) + { + goto error_ip_end; + } + } + + vn->erase_template_attribute("NETWORK_ADDRESS", st_addr); + + if (st_addr.empty()) + { + if ( ip_start != 0 && ip_end != 0 ) + { + if ( ip_end < ip_start ) + { + goto error_greater; + } + + return 0; + } + else + { + goto error_addr; + } + } + + // Check if the IP has a network prefix + pos = st_addr.find("/"); + + if ( pos != string::npos ) + { + string st_network_bits; + + st_network_bits = st_addr.substr(pos+1); + st_addr = st_addr.substr(0,pos); + + istringstream iss(st_network_bits); + iss >> network_bits; + + if ( network_bits > 32 ) + { + goto error_prefix; + } + + host_bits = 32 - network_bits; + } + else + { + vn->erase_template_attribute("NETWORK_MASK", st_mask); + + if ( !st_mask.empty() ) + { + // st_mask is in decimal format, e.g. 255.255.0.0 + // The number of trailing 0s is needed + + if ( Leases::Lease::ip_to_number(st_mask, net_mask) != 0 ) + { + goto error_netmask; + } + + host_bits = 0; + + while ( host_bits < 32 && + ((net_mask >> host_bits) & 1) != 1 ) + { + host_bits++; + } + } + else + { + vn->erase_template_attribute("NETWORK_SIZE",st_size); + + if ( st_size == "C" || st_size == "c" ) + { + host_bits = 8; + } + else if ( st_size == "B" || st_size == "b" ) + { + host_bits = 16; + } + else if ( st_size == "A" || st_size == "a" ) + { + host_bits = 24; + } + else + { + unsigned int size; + + if (!st_size.empty())//Assume it's a number + { + istringstream iss(st_size); + + iss >> size; + } + else + { + size = VirtualNetworkPool::default_size(); + } + + host_bits = (int) ceil(log(size+2)/log(2)); + } + } + } + + vn->remove_template_attribute("NETWORK_SIZE"); + + // Set the network mask + net_mask = 0xFFFFFFFF << host_bits; + Lease::ip_to_string(net_mask, st_mask); + + vn->replace_template_attribute("NETWORK_MASK", st_mask); + + if ( Leases::Lease::ip_to_number(st_addr,net_addr) != 0 ) + { + goto error_net_addr; + } + + if (net_addr != (net_mask & net_addr) ) + { + goto error_not_base_addr; + } + + // Set IP start/end + if ( ip_start == 0 ) + { + ip_start = net_addr + 1; + } + + if ( ip_end == 0 ) + { + ip_end = net_addr + (1 << host_bits) - 2; + } + + // Check range restrictions + if ( (ip_start & net_mask) != net_addr ) + { + goto error_range_ip_start; + } + + if ( (ip_end & net_mask) != net_addr ) + { + goto error_range_ip_end; + } + + if ( ip_end < ip_start ) + { + goto error_greater; + } + + return 0; + + +error_ip_start: + oss << "IP_START " << st_ip_start << " is not a valid IP."; + goto error_common; + +error_ip_end: + oss << "IP_END " << st_ip_end << " is not a valid IP."; + goto error_common; + +error_not_base_addr: + oss << "NETWORK_ADDRESS " << st_addr + << " is not a base address for the network mask " << st_mask << "."; + goto error_common; + +error_net_addr: + oss << "NETWORK_ADDRESS " << st_addr << " is not a valid IP."; + goto error_common; + +error_netmask: + oss << "NETWORK_MASK " << st_mask << " is not a valid network mask."; + goto error_common; + +error_prefix: + oss << "A CIDR prefix of " << network_bits << " bits is not valid."; + goto error_common; + +error_addr: + oss << "No NETWORK_ADDRESS in template for Virtual Network."; + goto error_common; + +error_range_ip_start: + oss << "IP_START " << st_ip_start << " is not part of the network " + << st_addr << "/" << 32-host_bits << "."; + goto error_common; + +error_range_ip_end: + oss << "IP_END " << st_ip_end << " is not part of the network " + << st_addr << "/" << 32-host_bits << "."; + goto error_common; + +error_greater: + Leases::Lease::ip_to_string(ip_start, st_ip_start); + Leases::Lease::ip_to_string(ip_end, st_ip_end); + + oss << "IP_START " << st_ip_start << " cannot be greater than the IP_END " + << st_ip_end << "."; + goto error_common; + + +error_common: + error_str = oss.str(); + return -1; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ int RangedLeases::get(int vid, string& ip, string& mac) { unsigned int num_ip; int rc = -1; - for (unsigned int i=0; i> size; - } - - if (size == 0) - { - size = default_size; - } - leases = new RangedLeases(db, oid, - size, mac_prefix, - network_address); + ip_start, + ip_end); } else if(type == FIXED) { @@ -192,9 +159,6 @@ error_type: ose << "Wrong type of Virtual Network: " << type; goto error_common; -error_addr: - ose << "Network address is not defined nid: " << oid; - error_common: NebulaLog::log("VNM", Log::ERROR, ose); return -1; @@ -211,8 +175,8 @@ int VirtualNetwork::insert(SqlDB * db, string& error_str) string pub; string vlan_attr; string s_type; + string ranged_error_str; - unsigned int default_size = VirtualNetworkPool::default_size(); unsigned int mac_prefix = VirtualNetworkPool::mac_prefix(); //-------------------------------------------------------------------------- @@ -299,45 +263,22 @@ int VirtualNetwork::insert(SqlDB * db, string& error_str) //-------------------------------------------------------------------------- if (type == VirtualNetwork::RANGED) { - string nclass = ""; - string naddr = ""; - int size = 0; - // retrieve specific information from template - get_template_attribute("NETWORK_ADDRESS",naddr); + int rc; - if (naddr.empty()) + rc = RangedLeases::process_template(this, ip_start, ip_end, + ranged_error_str); + + if ( rc != 0 ) { - goto error_addr; - } - - get_template_attribute("NETWORK_SIZE",nclass); - - if ( nclass == "B" || nclass == "b" ) - { - size = 65534; - } - else if ( nclass == "C" || nclass == "c" ) - { - size = 254; - } - else if (!nclass.empty())//Assume its a number - { - istringstream iss(nclass); - - iss >> size; - } - - if (size == 0) - { - size = default_size; + goto error_ranged; } leases = new RangedLeases(db, oid, - size, mac_prefix, - naddr); + ip_start, + ip_end); } else // VirtualNetwork::FIXED { @@ -390,8 +331,8 @@ error_update: ose << "Can not update Virtual Network."; goto error_common; -error_addr: - ose << "No NETWORK_ADDRESS in template for Virtual Network."; +error_ranged: + ose << ranged_error_str; goto error_common; error_null_leases: @@ -546,6 +487,21 @@ string& VirtualNetwork::to_xml_extended(string& xml, bool extended) const os << ""; } + if ( type == RANGED ) + { + string st_ip_start; + string st_ip_end; + + Leases::Lease::ip_to_string(ip_start, st_ip_start); + Leases::Lease::ip_to_string(ip_end, st_ip_end); + + os << + "" << + "" << st_ip_start << "" << + "" << st_ip_end << "" << + ""; + } + os << "" << public_obj << "" << ""<< total_leases << ""<< obj_template->to_xml(template_xml); @@ -614,6 +570,19 @@ int VirtualNetwork::from_xml(const string &xml_str) ObjectXML::free_nodes(content); + // Ranged Leases + if (type == RANGED) + { + string st_ip_start; + string st_ip_end; + + rc += xpath(st_ip_start, "/VNET/RANGE/IP_START", "0"); + rc += xpath(st_ip_end, "/VNET/RANGE/IP_END", "0"); + + Leases::Lease::ip_to_number(st_ip_start, ip_start); + Leases::Lease::ip_to_number(st_ip_end, ip_end); + } + if (rc != 0) { return -1; @@ -715,3 +684,29 @@ int VirtualNetwork::remove_leases(VirtualNetworkTemplate * leases_template, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ + +int VirtualNetwork::hold_leases(VirtualNetworkTemplate * leases_template, + string& error_msg) +{ + vector vector_leases; + + leases_template->get("LEASES", vector_leases); + + return leases->hold_leases(vector_leases, error_msg); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VirtualNetwork::free_leases(VirtualNetworkTemplate * leases_template, + string& error_msg) +{ + vector vector_leases; + + leases_template->get("LEASES", vector_leases); + + return leases->free_leases(vector_leases, error_msg); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/vnm/test/VirtualNetworkPoolTest.cc b/src/vnm/test/VirtualNetworkPoolTest.cc index 7cf06211be..d1744b2876 100644 --- a/src/vnm/test/VirtualNetworkPoolTest.cc +++ b/src/vnm/test/VirtualNetworkPoolTest.cc @@ -73,16 +73,16 @@ const string xmls[] = { "01230the_useroneadminNet number one1br1000130.10.0.150:20:20:20:20:200-1", - "12610the_useroneadminA virtual network0br0010", + "12610the_useroneadminA virtual network0br00192.168.0.1192.168.0.25410", "01330the_useroneadminNet number two1br1000130.10.2.150:20:20:20:20:200-1", }; const string xml_dump = - "010the_useroneadminNet number one1br1000120the_useroneadminA virtual network0br0010"; + "010the_useroneadminNet number one1br1000120the_useroneadminA virtual network0br00192.168.0.1192.168.0.25410"; const string xml_dump_where = - "120the_useroneadminA virtual network0br0010"; + "120the_useroneadminA virtual network0br00192.168.0.1192.168.0.25410"; /* ************************************************************************* */ /* ************************************************************************* */ @@ -180,6 +180,8 @@ class VirtualNetworkPoolTest : public PoolTest CPPUNIT_TEST (del_lease_nonexistent_ip); CPPUNIT_TEST (del_lease_used_ip); + CPPUNIT_TEST (range_definition); + CPPUNIT_TEST_SUITE_END (); protected: @@ -411,16 +413,16 @@ public: "TYPE = RANGED\n" "BRIDGE = br0\n" "NETWORK_SIZE = B\n" - "NETWORK_ADDRESS = 192.168.1.0\n", + "NETWORK_ADDRESS = 192.168.0.0\n", - // Size "X", defaults to 128 + // Size 126 "NAME = \"Net D\"\n" "TYPE = RANGED\n" "BRIDGE = br0\n" - "NETWORK_SIZE = X\n" + "NETWORK_SIZE = 126\n" "NETWORK_ADDRESS = 192.168.1.0\n", - // Size 32 + // Size 30 "NAME = \"Net E\"\n" "TYPE = RANGED\n" "BRIDGE = br0\n" @@ -428,7 +430,7 @@ public: "NETWORK_ADDRESS = 192.168.1.0\n" }; - unsigned int sizes[7]={1,3,256,256,65536,128,32}; + unsigned int sizes[7]={1,3,254,254,65534,126,30}; int oid[7]; for (int i = 0 ; i < 7 ; i++) @@ -695,7 +697,7 @@ public: CPPUNIT_ASSERT( rc != 0 ); - // Ask for two more IPs + // Ask for the rest of IPs vn->lock(); rc = vn->get_lease(123, ip, mac, bridge); vn->unlock(); @@ -708,12 +710,28 @@ public: CPPUNIT_ASSERT( rc == 0 ); + vn->lock(); + rc = vn->get_lease(457, ip, mac, bridge); + vn->unlock(); + + CPPUNIT_ASSERT( rc == 0 ); + + vn->lock(); + rc = vn->get_lease(458, ip, mac, bridge); + vn->unlock(); + + CPPUNIT_ASSERT( rc == 0 ); + + vn->lock(); + rc = vn->get_lease(459, ip, mac, bridge); + vn->unlock(); + + CPPUNIT_ASSERT( rc == 0 ); // All IPs are now used vn->lock(); rc = vn->get_lease(789, ip, mac, bridge); vn->unlock(); - CPPUNIT_ASSERT( rc != 0 ); // Release one of the 3 IPs @@ -1626,6 +1644,134 @@ public: CPPUNIT_ASSERT( rc != 0 ); CPPUNIT_ASSERT( error_str != "" ); } + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + + void range_definition() + { + VirtualNetworkPoolFriend * vnpool = + static_cast(pool); + + int rc; + VirtualNetwork* vnet; + + int oid; + string xml_str; + string xpath; + string err; + + // All these templates should create the same range + string templ[] = { + "NAME = R\n" + "TYPE = RANGED\n" + "BRIDGE = vbr0\n" + "NETWORK_ADDRESS = 10.10.10.0\n" + "NETWORK_SIZE = C\n", + + "NAME = R\n" + "TYPE = RANGED\n" + "BRIDGE = vbr0\n" + "NETWORK_ADDRESS = 10.10.10.0\n" + "NETWORK_SIZE = 254\n", + + "NAME = R\n" + "TYPE = RANGED\n" + "BRIDGE = vbr0\n" + "NETWORK_ADDRESS = 10.10.10.0/24\n", + + "NAME = R\n" + "TYPE = RANGED\n" + "BRIDGE = vbr0\n" + "NETWORK_ADDRESS = 10.10.10.0\n" + "NETWORK_MASK = 255.255.255.0\n", + + + + "NAME = R\n" + "TYPE = RANGED\n" + "BRIDGE = vbr0\n" + "NETWORK_ADDRESS = 10.10.10.0/24\n" + "IP_START = 10.10.10.17\n", + + "NAME = R\n" + "TYPE = RANGED\n" + "BRIDGE = vbr0\n" + "NETWORK_ADDRESS = 10.10.10.0/24\n" + "IP_END = 10.10.10.41\n", + + "NAME = R\n" + "TYPE = RANGED\n" + "BRIDGE = vbr0\n" + "NETWORK_ADDRESS = 10.10.10.0/24\n" + "IP_START = 10.10.10.17\n" + "IP_END = 10.10.10.41\n", + + + + "NAME = R\n" + "TYPE = RANGED\n" + "BRIDGE = vbr0\n" + "IP_START = 10.10.10.17\n" + "IP_END = 10.10.10.41\n", + + "NAME = R\n" + "TYPE = RANGED\n" + "BRIDGE = vbr0\n" + "NETWORK_ADDRESS = 10.10.10.0\n", + }; + + string ip_start[] = { + "10.10.10.1", + "10.10.10.1", + "10.10.10.1", + "10.10.10.1", + + "10.10.10.17", + "10.10.10.1", + "10.10.10.17", + + "10.10.10.17", + + "10.10.10.1", + }; + + string ip_end[] = { + "10.10.10.254", + "10.10.10.254", + "10.10.10.254", + "10.10.10.254", + + "10.10.10.254", + "10.10.10.41", + "10.10.10.41", + + "10.10.10.41", + + "10.10.10.126", + }; + + + for (int i = 0 ; i < 9 ; i++) + { + rc = vnpool->allocate(uids[0], templ[i], &oid); + + CPPUNIT_ASSERT( rc >= 0 ); + + vnet = vnpool->get(oid, false); + CPPUNIT_ASSERT( vnet != 0 ); + + vnet->to_xml_extended(xml_str); + + ObjectXML::xpath_value(xpath, xml_str.c_str(), "/VNET/RANGE/IP_START" ); + CPPUNIT_ASSERT( xpath == ip_start[i] ); + + ObjectXML::xpath_value(xpath, xml_str.c_str(), "/VNET/RANGE/IP_END" ); + CPPUNIT_ASSERT( xpath == ip_end[i] ); + + vnpool->drop(vnet, err); + } + } }; /* ************************************************************************* */