From 83e82830c8fa6951e21f5f2d7fd8270d8dc55e59 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= <cmartins@fdi.ucm.es>
Date: Fri, 25 Nov 2011 10:02:17 -0800
Subject: [PATCH 01/15] Feature #602: Refactor Ranged VNets to store first and
 last IP of the range

---
 include/FixedLeases.h     |  8 +---
 include/Leases.h          | 25 ++++++-----
 include/RangedLeases.h    | 14 ++----
 include/VirtualNetwork.h  |  3 ++
 src/vnm/FixedLeases.cc    |  2 +-
 src/vnm/RangedLeases.cc   | 29 ++++--------
 src/vnm/VirtualNetwork.cc | 92 ++++++++++++++++++++++-----------------
 7 files changed, 83 insertions(+), 90 deletions(-)

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..5927f36f14 100644
--- a/include/Leases.h
+++ b/include/Leases.h
@@ -40,7 +40,7 @@ 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){};
 
@@ -230,13 +230,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 +249,11 @@ protected:
      */
     int n_used;
 
+    /**
+     *  The default MAC prefix for the Leases
+     */
+    unsigned int mac_prefix;
+
     // -------------------------------------------------------------------------
     // DataBase implementation variables
     // -------------------------------------------------------------------------
@@ -286,11 +291,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..4f97acb821 100644
--- a/include/RangedLeases.h
+++ b/include/RangedLeases.h
@@ -30,9 +30,9 @@ 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(){};
 
@@ -105,15 +105,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/VirtualNetwork.h b/include/VirtualNetwork.h
index be02e86954..9146d69f97 100644
--- a/include/VirtualNetwork.h
+++ b/include/VirtualNetwork.h
@@ -222,6 +222,9 @@ private:
      */
     Leases *    leases;
 
+    unsigned int ip_start;
+    unsigned int ip_end;
+
     // *************************************************************************
     // DataBase implementation (Private)
     // *************************************************************************
diff --git a/src/vnm/FixedLeases.cc b/src/vnm/FixedLeases.cc
index 83180c2a92..fc14480c74 100644
--- a/src/vnm/FixedLeases.cc
+++ b/src/vnm/FixedLeases.cc
@@ -25,7 +25,7 @@ FixedLeases::FixedLeases(
         int                         _oid,
         unsigned int                _mac_prefix,
         vector<const Attribute*>&   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/RangedLeases.cc b/src/vnm/RangedLeases.cc
index d74f599e17..c94d59118b 100644
--- a/src/vnm/RangedLeases.cc
+++ b/src/vnm/RangedLeases.cc
@@ -17,7 +17,6 @@
 
 #include "RangedLeases.h"
 #include "Nebula.h"
-#include <cmath>
 
 /* ************************************************************************** */
 /* Ranged Leases class                                                        */
@@ -26,21 +25,13 @@
 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;
 }
 
 /* ************************************************************************** */
@@ -52,9 +43,9 @@ int RangedLeases::get(int vid, string&  ip, string&  mac)
     unsigned int num_ip;
     int          rc = -1;
 
-    for (unsigned int i=0; i<size; i++, current++)
+    for ( unsigned int i=0; i<size; i++, current = (current+1)%size )
     {
-        num_ip = network_address + (current%(size-2)) + 1;
+        num_ip = ip_start + current;
 
         if (check(num_ip) == false)
         {
@@ -85,7 +76,6 @@ int RangedLeases::set(int vid, const string&  ip, string&  mac)
 {
     unsigned int num_ip;
     unsigned int num_mac[2];
-    unsigned int net;
     int          rc;
 
     rc = Leases::Lease::ip_to_number(ip,num_ip);
@@ -95,10 +85,7 @@ int RangedLeases::set(int vid, const string&  ip, string&  mac)
         return -1;
     }
 
-    net =  0xFFFFFFFF << (int) ceil(log(size)/log(2));
-    net &= num_ip;
-
-    if ( net != network_address )
+    if ( num_ip < ip_start || ip_end < num_ip )
     {
         return -1;
     }
diff --git a/src/vnm/VirtualNetwork.cc b/src/vnm/VirtualNetwork.cc
index 520ba533b5..c3c125cbbb 100644
--- a/src/vnm/VirtualNetwork.cc
+++ b/src/vnm/VirtualNetwork.cc
@@ -25,6 +25,8 @@
 
 #include "AuthManager.h"
 
+#include <cmath>
+
 /* ************************************************************************** */
 /* Virtual Network :: Constructor/Destructor                                  */
 /* ************************************************************************** */
@@ -119,49 +121,16 @@ int VirtualNetwork::select_leases(SqlDB * db)
 
     string          network_address;
 
-    unsigned int default_size = VirtualNetworkPool::default_size();
     unsigned int mac_prefix   = VirtualNetworkPool::mac_prefix();
 
     //Get the leases
     if (type == RANGED)
     {
-        string  nclass = "";
-        int     size = 0;
-
-        // retrieve specific information from the template
-        get_template_attribute("NETWORK_ADDRESS",network_address);
-
-        if (network_address.empty())
-        {
-            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 it's a number
-        {
-            istringstream iss(nclass);
-            iss >> 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)
     {
@@ -190,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;
@@ -292,6 +258,7 @@ int VirtualNetwork::insert(SqlDB * db, string& error_str)
         string nclass = "";
         string naddr  = "";
         int    size   = 0;
+        unsigned int net_addr;
 
         // retrieve specific information from template
         get_template_attribute("NETWORK_ADDRESS",naddr);
@@ -311,7 +278,7 @@ int VirtualNetwork::insert(SqlDB * db, string& error_str)
         {
             size = 254;
         }
-        else if (!nclass.empty())//Assume its a number
+        else if (!nclass.empty())//Assume it's a number
         {
             istringstream iss(nclass);
 
@@ -323,11 +290,26 @@ int VirtualNetwork::insert(SqlDB * db, string& error_str)
             size = default_size;
         }
 
+        Leases::Lease::ip_to_number(naddr,net_addr);
+
+        int shift;
+        shift = (int) ceil(log(size+2)/log(2));
+        size = (1 << shift) - 2;
+        unsigned int network_mask =  0xFFFFFFFF << shift;
+
+        if (net_addr != (network_mask & net_addr) )
+        {
+            // TODO: net_addr is not a valid network address, should end with 0s
+        }
+
+        ip_start = net_addr + 1;
+        ip_end   = ip_start + size -1;
+
         leases = new RangedLeases(db,
                                   oid,
-                                  size,
                                   mac_prefix,
-                                  naddr);
+                                  ip_start,
+                                  ip_end);
     }
     else // VirtualNetwork::FIXED
     {
@@ -527,6 +509,21 @@ string& VirtualNetwork::to_xml_extended(string& xml, bool extended) const
         os << "<VLAN_ID>" << vlan_id << "</VLAN_ID>";
     }
 
+    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 <<
+            "<RANGE>" <<
+                "<IP_START>" << st_ip_start << "</IP_START>" <<
+                "<IP_END>"   << st_ip_end   << "</IP_END>"   <<
+            "</RANGE>";
+    }
+
     os  <<  "<PUBLIC>"      << public_obj   << "</PUBLIC>"      <<
             "<TOTAL_LEASES>"<< total_leases << "</TOTAL_LEASES>"<<
             obj_template->to_xml(template_xml);
@@ -585,6 +582,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;

From e894fb5d373508c789866075a9b697e9c2ae7600 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= <cmartins@fdi.ucm.es>
Date: Mon, 28 Nov 2011 16:30:08 +0100
Subject: [PATCH 02/15] Feature #602: Make Network size definition more
 flexible. The netmask is generated from the given size

The Network size can be defined as:
  * NETWORK_ADDRESS attribute: 19.2168.30.0/24
  * SIZE: Letter (a,b,c) or number of hosts
  * NETWORK_MASK: 255.255.255.0 creates a network of 254 hosts
---
 src/vnm/VirtualNetwork.cc | 115 +++++++++++++++++++++++++++++---------
 1 file changed, 88 insertions(+), 27 deletions(-)

diff --git a/src/vnm/VirtualNetwork.cc b/src/vnm/VirtualNetwork.cc
index c3c125cbbb..899154538d 100644
--- a/src/vnm/VirtualNetwork.cc
+++ b/src/vnm/VirtualNetwork.cc
@@ -255,53 +255,114 @@ int VirtualNetwork::insert(SqlDB * db, string& error_str)
     //--------------------------------------------------------------------------
     if (type == VirtualNetwork::RANGED)
     {
-        string nclass = "";
-        string naddr  = "";
-        int    size   = 0;
+        string st_size = "";
+        string st_addr  = "";
+        string st_mask  = "";
+
+        unsigned int size = default_size;
+        unsigned int host_bits;
+        unsigned int network_bits;
+
         unsigned int net_addr;
+        unsigned int net_mask;
+        size_t       pos;
 
         // retrieve specific information from template
-        get_template_attribute("NETWORK_ADDRESS",naddr);
 
-        if (naddr.empty())
+        erase_template_attribute("NETWORK_ADDRESS",st_addr);
+
+        if (st_addr.empty())
         {
             goto error_addr;
         }
 
-        get_template_attribute("NETWORK_SIZE",nclass);
+        // Check if the IP has a network prefix
+        pos = st_addr.find("/");
 
-        if ( nclass == "B" || nclass == "b"  )
+        if ( pos != string::npos )
         {
-            size = 65534;
-        }
-        else if ( nclass == "C" || nclass == "c"  )
-        {
-            size = 254;
-        }
-        else if (!nclass.empty())//Assume it's a number
-        {
-            istringstream iss(nclass);
+            string st_network_bits;
 
-            iss >> size;
+            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 )
+            {
+                // TODO wrong prefix
+            }
+
+            host_bits = 32 - network_bits;
+        }
+        else
+        {
+            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
+
+                Leases::Lease::ip_to_number(st_mask, net_mask);
+
+                host_bits = 0;
+
+                while ( host_bits < 32 &&
+                        ((net_mask >> host_bits) & 1) != 1 )
+                {
+                    host_bits++;
+                }
+            }
+            else
+            {
+                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
+                {
+                    size = default_size;
+
+                    if (!st_size.empty())//Assume it's a number
+                    {
+                        istringstream iss(st_size);
+
+                        iss >> size;
+                    }
+
+                    host_bits = (int) ceil(log(size+2)/log(2));
+                }
+            }
         }
 
-        if (size == 0)
-        {
-            size = default_size;
-        }
+        remove_template_attribute("NETWORK_SIZE");
 
-        Leases::Lease::ip_to_number(naddr,net_addr);
+        // Set the network mask
+        net_mask = ( 0xFFFFFFFF << host_bits ) & 0xFFFFFFFF;
+        Leases::Lease::ip_to_string(net_mask, st_mask);
+        replace_template_attribute("NETWORK_MASK", st_mask);
 
-        int shift;
-        shift = (int) ceil(log(size+2)/log(2));
-        size = (1 << shift) - 2;
-        unsigned int network_mask =  0xFFFFFFFF << shift;
+        Leases::Lease::ip_to_number(st_addr,net_addr);
 
-        if (net_addr != (network_mask & net_addr) )
+        if (net_addr != (net_mask & net_addr) )
         {
             // TODO: net_addr is not a valid network address, should end with 0s
         }
 
+        size = (1 << host_bits) - 2;
+
         ip_start = net_addr + 1;
         ip_end   = ip_start + size -1;
 

From 4fcf406c0c8b51e05007f04ddb5bb95ffa8a06d3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= <cmartins@fdi.ucm.es>
Date: Mon, 28 Nov 2011 16:47:11 +0100
Subject: [PATCH 03/15] Feature #602: Show RANGE/IP_START and RANGE/IP_END in
 'onevnet show'

---
 src/cli/one_helper/onevnet_helper.rb | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/cli/one_helper/onevnet_helper.rb b/src/cli/one_helper/onevnet_helper.rb
index 3d72e196af..71ead0d55f 100644
--- a/src/cli/one_helper/onevnet_helper.rb
+++ b/src/cli/one_helper/onevnet_helper.rb
@@ -66,6 +66,13 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper
 
         puts vn.template_str(false)
 
+        if vn.type_str == "RANGED"
+            puts
+            CLIHelper.print_header(str_h1 % ["RANGE"], false)
+            puts str % ["IP_START", vn['RANGE/IP_START']]
+            puts str % ["IP_END", vn['RANGE/IP_END']]
+        end
+
         leases_str = vn.template_like_str('/VNET/LEASES', false)
 
         if !leases_str.empty?

From effb4a57126b862b247916675ee71fa326fbd233 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= <cmartins@fdi.ucm.es>
Date: Mon, 28 Nov 2011 17:24:46 +0100
Subject: [PATCH 04/15] Feature #602: Refactorin of the Range creation code.
 New method RangedLeases::process_template

---
 include/RangedLeases.h    |  12 ++++
 src/vnm/RangedLeases.cc   | 132 ++++++++++++++++++++++++++++++++++++++
 src/vnm/VirtualNetwork.cc | 118 +++-------------------------------
 3 files changed, 152 insertions(+), 110 deletions(-)

diff --git a/include/RangedLeases.h b/include/RangedLeases.h
index 4f97acb821..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;
 
@@ -36,6 +37,17 @@ public:
 
     ~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
diff --git a/src/vnm/RangedLeases.cc b/src/vnm/RangedLeases.cc
index c94d59118b..26fb6940dd 100644
--- a/src/vnm/RangedLeases.cc
+++ b/src/vnm/RangedLeases.cc
@@ -18,6 +18,8 @@
 #include "RangedLeases.h"
 #include "Nebula.h"
 
+#include <cmath>
+
 /* ************************************************************************** */
 /* Ranged Leases class                                                        */
 /* ************************************************************************** */
@@ -37,6 +39,136 @@ RangedLeases::RangedLeases(
 /* ************************************************************************** */
 /* 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  = "";
+
+    int default_size = VirtualNetworkPool::default_size();
+    unsigned int size = default_size;
+    unsigned int host_bits;
+    unsigned int network_bits;
+
+    unsigned int net_addr;
+    unsigned int net_mask;
+    size_t       pos;
+
+    // retrieve specific information from template
+
+    vn->erase_template_attribute("NETWORK_ADDRESS",st_addr);
+
+    if (st_addr.empty())
+    {
+        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 )
+        {
+            // TODO wrong 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
+
+            Leases::Lease::ip_to_number(st_mask, net_mask);
+
+            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
+            {
+                size = default_size;
+
+                if (!st_size.empty())//Assume it's a number
+                {
+                    istringstream iss(st_size);
+
+                    iss >> 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 ) & 0xFFFFFFFF;
+    Lease::ip_to_string(net_mask, st_mask);
+    vn->replace_template_attribute("NETWORK_MASK", st_mask);
+
+    Leases::Lease::ip_to_number(st_addr,net_addr);
+
+    if (net_addr != (net_mask & net_addr) )
+    {
+        // TODO: net_addr is not a valid network address, should end with 0s
+    }
+
+    size = (1 << host_bits) - 2;
+
+    ip_start = net_addr + 1;
+    ip_end   = ip_start + size -1;
+
+    return 0;
+
+error_addr:
+    oss << "No NETWORK_ADDRESS in template for Virtual Network.";
+    goto error_common;
+
+error_common:
+    error_str = oss.str();
+    return -1;
+}
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 
 int RangedLeases::get(int vid, string&  ip, string&  mac)
 {
diff --git a/src/vnm/VirtualNetwork.cc b/src/vnm/VirtualNetwork.cc
index 899154538d..72a833d407 100644
--- a/src/vnm/VirtualNetwork.cc
+++ b/src/vnm/VirtualNetwork.cc
@@ -25,8 +25,6 @@
 
 #include "AuthManager.h"
 
-#include <cmath>
-
 /* ************************************************************************** */
 /* Virtual Network :: Constructor/Destructor                                  */
 /* ************************************************************************** */
@@ -174,8 +172,8 @@ int VirtualNetwork::insert(SqlDB * db, string& error_str)
 
     string          pub;
     string          s_type;
+    string          ranged_error_str;
 
-    unsigned int default_size = VirtualNetworkPool::default_size();
     unsigned int mac_prefix   = VirtualNetworkPool::mac_prefix();
 
     //--------------------------------------------------------------------------
@@ -255,117 +253,17 @@ int VirtualNetwork::insert(SqlDB * db, string& error_str)
     //--------------------------------------------------------------------------
     if (type == VirtualNetwork::RANGED)
     {
-        string st_size = "";
-        string st_addr  = "";
-        string st_mask  = "";
 
-        unsigned int size = default_size;
-        unsigned int host_bits;
-        unsigned int network_bits;
+        int rc;
 
-        unsigned int net_addr;
-        unsigned int net_mask;
-        size_t       pos;
+        rc = RangedLeases::process_template(this, ip_start, ip_end,
+                ranged_error_str);
 
-        // retrieve specific information from template
-
-        erase_template_attribute("NETWORK_ADDRESS",st_addr);
-
-        if (st_addr.empty())
+        if ( rc != 0 )
         {
-            goto error_addr;
+            goto error_ranged;
         }
 
-        // 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 )
-            {
-                // TODO wrong prefix
-            }
-
-            host_bits = 32 - network_bits;
-        }
-        else
-        {
-            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
-
-                Leases::Lease::ip_to_number(st_mask, net_mask);
-
-                host_bits = 0;
-
-                while ( host_bits < 32 &&
-                        ((net_mask >> host_bits) & 1) != 1 )
-                {
-                    host_bits++;
-                }
-            }
-            else
-            {
-                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
-                {
-                    size = default_size;
-
-                    if (!st_size.empty())//Assume it's a number
-                    {
-                        istringstream iss(st_size);
-
-                        iss >> size;
-                    }
-
-                    host_bits = (int) ceil(log(size+2)/log(2));
-                }
-            }
-        }
-
-        remove_template_attribute("NETWORK_SIZE");
-
-        // Set the network mask
-        net_mask = ( 0xFFFFFFFF << host_bits ) & 0xFFFFFFFF;
-        Leases::Lease::ip_to_string(net_mask, st_mask);
-        replace_template_attribute("NETWORK_MASK", st_mask);
-
-        Leases::Lease::ip_to_number(st_addr,net_addr);
-
-        if (net_addr != (net_mask & net_addr) )
-        {
-            // TODO: net_addr is not a valid network address, should end with 0s
-        }
-
-        size = (1 << host_bits) - 2;
-
-        ip_start = net_addr + 1;
-        ip_end   = ip_start + size -1;
-
         leases = new RangedLeases(db,
                                   oid,
                                   mac_prefix,
@@ -423,8 +321,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:

From 9791ece838364d7992911b98bac0d03c240d3194 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= <cmartins@fdi.ucm.es>
Date: Mon, 28 Nov 2011 18:10:00 +0100
Subject: [PATCH 05/15] Feature #602: Add support for IP_START and IP_END
 redefinition in Ranged networks

---
 src/vnm/Leases.cc       |  5 ++++
 src/vnm/RangedLeases.cc | 64 +++++++++++++++++++++++++++++++++++------
 2 files changed, 60 insertions(+), 9 deletions(-)

diff --git a/src/vnm/Leases.cc b/src/vnm/Leases.cc
index 17dc998d07..fa0eedabb1 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;
     }
diff --git a/src/vnm/RangedLeases.cc b/src/vnm/RangedLeases.cc
index 26fb6940dd..ce860d673b 100644
--- a/src/vnm/RangedLeases.cc
+++ b/src/vnm/RangedLeases.cc
@@ -48,8 +48,10 @@ int RangedLeases::process_template(VirtualNetwork* vn,
     string st_addr  = "";
     string st_mask  = "";
 
-    int default_size = VirtualNetworkPool::default_size();
-    unsigned int size = default_size;
+    string st_ip_start  = "";
+    string st_ip_end    = "";
+
+    unsigned int size = VirtualNetworkPool::default_size();
     unsigned int host_bits;
     unsigned int network_bits;
 
@@ -57,13 +59,41 @@ int RangedLeases::process_template(VirtualNetwork* vn,
     unsigned int net_mask;
     size_t       pos;
 
-    // retrieve specific information from template
+    ip_start = 0;
+    ip_end   = 0;
 
-    vn->erase_template_attribute("NETWORK_ADDRESS",st_addr);
+    // 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())
     {
-        goto error_addr;
+        if ( ip_start != 0 && ip_end != 0 )
+        {
+            return 0;
+        }
+        else
+        {
+            goto error_addr;
+        }
     }
 
     // Check if the IP has a network prefix
@@ -123,8 +153,6 @@ int RangedLeases::process_template(VirtualNetwork* vn,
             }
             else
             {
-                size = default_size;
-
                 if (!st_size.empty())//Assume it's a number
                 {
                     istringstream iss(st_size);
@@ -153,11 +181,29 @@ int RangedLeases::process_template(VirtualNetwork* vn,
 
     size = (1 << host_bits) - 2;
 
-    ip_start = net_addr + 1;
-    ip_end   = ip_start + size -1;
+    // TODO: check that start < end; ip_start & ip_end are part of the network
+
+    if ( ip_start == 0 )
+    {
+        ip_start = net_addr + 1;
+    }
+
+    if ( ip_end == 0 )
+    {
+        ip_end   = net_addr + size;
+    }
 
     return 0;
 
+
+error_ip_start:
+    oss << "IP_START is not a valid IP.";
+    goto error_common;
+
+error_ip_end:
+    oss << "IP_END is not a valid IP.";
+    goto error_common;
+
 error_addr:
     oss << "No NETWORK_ADDRESS in template for Virtual Network.";
     goto error_common;

From 07bc7d01549178defbef55205f22b4ce3e44ad6a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= <cmartins@fdi.ucm.es>
Date: Mon, 28 Nov 2011 19:07:44 +0100
Subject: [PATCH 06/15] Feature #602: Add error checks in Ranged network
 creation

---
 src/vnm/RangedLeases.cc | 78 ++++++++++++++++++++++++++++++++++++-----
 1 file changed, 70 insertions(+), 8 deletions(-)

diff --git a/src/vnm/RangedLeases.cc b/src/vnm/RangedLeases.cc
index ce860d673b..84c1bddaf0 100644
--- a/src/vnm/RangedLeases.cc
+++ b/src/vnm/RangedLeases.cc
@@ -88,6 +88,11 @@ int RangedLeases::process_template(VirtualNetwork* vn,
     {
         if ( ip_start != 0 && ip_end != 0 )
         {
+            if ( ip_end < ip_start )
+            {
+                goto error_greater;
+            }
+
             return 0;
         }
         else
@@ -111,7 +116,7 @@ int RangedLeases::process_template(VirtualNetwork* vn,
 
         if ( network_bits > 32 )
         {
-            // TODO wrong prefix
+            goto error_prefix;
         }
 
         host_bits = 32 - network_bits;
@@ -125,7 +130,10 @@ int RangedLeases::process_template(VirtualNetwork* vn,
             // st_mask is in decimal format, e.g. 255.255.0.0
             // The number of trailing 0s is needed
 
-            Leases::Lease::ip_to_number(st_mask, net_mask);
+            if ( Leases::Lease::ip_to_number(st_mask, net_mask) != 0 )
+            {
+                goto error_netmask;
+            }
 
             host_bits = 0;
 
@@ -172,17 +180,19 @@ int RangedLeases::process_template(VirtualNetwork* vn,
     Lease::ip_to_string(net_mask, st_mask);
     vn->replace_template_attribute("NETWORK_MASK", st_mask);
 
-    Leases::Lease::ip_to_number(st_addr,net_addr);
+    if ( Leases::Lease::ip_to_number(st_addr,net_addr) != 0 )
+    {
+        goto error_net_addr;
+    }
 
     if (net_addr != (net_mask & net_addr) )
     {
-        // TODO: net_addr is not a valid network address, should end with 0s
+        goto error_not_base_addr;
     }
 
     size = (1 << host_bits) - 2;
 
-    // TODO: check that start < end; ip_start & ip_end are part of the network
-
+    // Set IP start/end
     if ( ip_start == 0 )
     {
         ip_start = net_addr + 1;
@@ -193,21 +203,73 @@ int RangedLeases::process_template(VirtualNetwork* vn,
         ip_end   = net_addr + size;
     }
 
+    // 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 is not a valid IP.";
+    oss << "IP_START " << st_ip_start << " is not a valid IP.";
     goto error_common;
 
 error_ip_end:
-    oss << "IP_END is not a valid IP.";
+    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;

From 4904cc964beb37122f169eaaaf935f3ed24be160 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= <cmartins@fdi.ucm.es>
Date: Tue, 29 Nov 2011 16:12:00 +0100
Subject: [PATCH 07/15] Feature #965: New one.vn.hold and one.vn.release
 methods to mark IPs as used, without an associated VM. Includes Ruby OCA and
 CLI

---
 include/Leases.h                          |  20 +++++
 include/RequestManagerVirtualNetwork.h    |  38 ++++++++
 include/VirtualNetwork.h                  |  23 ++++-
 src/cli/onevnet                           |  23 ++++-
 src/oca/ruby/OpenNebula/VirtualNetwork.rb |  30 ++++++-
 src/rm/RequestManager.cc                  |   4 +
 src/rm/RequestManagerVirtualNetwork.cc    |   2 +-
 src/vnm/Leases.cc                         | 103 +++++++++++++++++++---
 src/vnm/VirtualNetwork.cc                 |  26 ++++++
 9 files changed, 250 insertions(+), 19 deletions(-)

diff --git a/include/Leases.h b/include/Leases.h
index 5927f36f14..bb8453e53b 100644
--- a/include/Leases.h
+++ b/include/Leases.h
@@ -102,6 +102,26 @@ public:
     virtual int remove_leases(vector<const Attribute*>& 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<const Attribute*>& 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<const Attribute*>& vector_leases, string& error_msg);
+
     // -------------------------------------------------------------------------
     // -------------------------------------------------------------------------
 
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 9146d69f97..6625c260b4 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
diff --git a/src/cli/onevnet b/src/cli/onevnet
index 72ab53716a..b2ba672371 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/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/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/Leases.cc b/src/vnm/Leases.cc
index fa0eedabb1..c159294625 100644
--- a/src/vnm/Leases.cc
+++ b/src/vnm/Leases.cc
@@ -386,23 +386,11 @@ int Leases::update(SqlDB * db)
 
 bool Leases::check(const string& ip)
 {
-    map<unsigned int,Lease *>::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);
 }
 
 /* -------------------------------------------------------------------------- */
@@ -424,6 +412,95 @@ bool Leases::check(unsigned int ip)
     }
 }
 
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+int Leases::hold_leases(vector<const Attribute*>&   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<const VectorAttribute *>(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<const Attribute*>&   vector_leases,
+                        string&                     error_msg)
+{
+    const VectorAttribute * single_attr_lease = 0;
+    map<unsigned int,Lease *>::iterator it;
+
+    unsigned int    i_ip;
+    string          st_ip;
+    string          mac;
+
+    if ( vector_leases.size() > 0 )
+    {
+        single_attr_lease =
+                dynamic_cast<const VectorAttribute *>(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/VirtualNetwork.cc b/src/vnm/VirtualNetwork.cc
index 72a833d407..5fa53f2115 100644
--- a/src/vnm/VirtualNetwork.cc
+++ b/src/vnm/VirtualNetwork.cc
@@ -646,3 +646,29 @@ int VirtualNetwork::remove_leases(VirtualNetworkTemplate * leases_template,
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
+
+int VirtualNetwork::hold_leases(VirtualNetworkTemplate * leases_template,
+                                string&                  error_msg)
+{
+    vector<const Attribute *> 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<const Attribute *> vector_leases;
+
+    leases_template->get("LEASES", vector_leases);
+
+    return leases->free_leases(vector_leases, error_msg);
+}
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */

From 05e40b5b6f41c3691e0e0b7a8ea6d99ad80056d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= <cmartins@fdi.ucm.es>
Date: Tue, 29 Nov 2011 18:09:19 +0100
Subject: [PATCH 08/15] Feature #602: Small bugfixes

---
 include/Leases.h        | 2 +-
 src/vnm/RangedLeases.cc | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/Leases.h b/include/Leases.h
index bb8453e53b..74a04d7928 100644
--- a/include/Leases.h
+++ b/include/Leases.h
@@ -42,7 +42,7 @@ public:
      */
     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()
     {
diff --git a/src/vnm/RangedLeases.cc b/src/vnm/RangedLeases.cc
index 84c1bddaf0..d992ad29c0 100644
--- a/src/vnm/RangedLeases.cc
+++ b/src/vnm/RangedLeases.cc
@@ -176,7 +176,7 @@ int RangedLeases::process_template(VirtualNetwork* vn,
     vn->remove_template_attribute("NETWORK_SIZE");
 
     // Set the network mask
-    net_mask = ( 0xFFFFFFFF << host_bits ) & 0xFFFFFFFF;
+    net_mask = 0xFFFFFFFF << host_bits;
     Lease::ip_to_string(net_mask, st_mask);
     vn->replace_template_attribute("NETWORK_MASK", st_mask);
 

From 8ef3c966a4ea28c265ffe74e7dc183187c809587 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= <cmartins@fdi.ucm.es>
Date: Tue, 29 Nov 2011 18:10:05 +0100
Subject: [PATCH 09/15] Feature #602: Fix tests

---
 src/vnm/test/VirtualNetworkPoolTest.cc | 36 +++++++++++++++++++-------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/src/vnm/test/VirtualNetworkPoolTest.cc b/src/vnm/test/VirtualNetworkPoolTest.cc
index 2d5801309c..556f6884a6 100644
--- a/src/vnm/test/VirtualNetworkPoolTest.cc
+++ b/src/vnm/test/VirtualNetworkPoolTest.cc
@@ -73,16 +73,16 @@ const string xmls[] =
 {
     "<VNET><ID>0</ID><UID>123</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>Net number one</NAME><TYPE>1</TYPE><BRIDGE>br1</BRIDGE><PUBLIC>0</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE></TEMPLATE><LEASES><LEASE><IP>130.10.0.1</IP><MAC>50:20:20:20:20:20</MAC><USED>0</USED><VID>-1</VID></LEASE></LEASES></VNET>",
 
-    "<VNET><ID>1</ID><UID>261</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>A virtual network</NAME><TYPE>0</TYPE><BRIDGE>br0</BRIDGE><PUBLIC>1</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE><NETWORK_ADDRESS><![CDATA[192.168.0.0]]></NETWORK_ADDRESS><NETWORK_SIZE><![CDATA[C]]></NETWORK_SIZE></TEMPLATE><LEASES></LEASES></VNET>",
+    "<VNET><ID>1</ID><UID>261</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>A virtual network</NAME><TYPE>0</TYPE><BRIDGE>br0</BRIDGE><RANGE><IP_START>192.168.0.1</IP_START><IP_END>192.168.0.254</IP_END></RANGE><PUBLIC>1</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE><NETWORK_MASK><![CDATA[255.255.255.0]]></NETWORK_MASK></TEMPLATE><LEASES></LEASES></VNET>",
 
     "<VNET><ID>0</ID><UID>133</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>Net number two</NAME><TYPE>1</TYPE><BRIDGE>br1</BRIDGE><PUBLIC>0</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE></TEMPLATE><LEASES><LEASE><IP>130.10.2.1</IP><MAC>50:20:20:20:20:20</MAC><USED>0</USED><VID>-1</VID></LEASE></LEASES></VNET>",
 };
 
 const string xml_dump =
-    "<VNET_POOL><VNET><ID>0</ID><UID>1</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>Net number one</NAME><TYPE>1</TYPE><BRIDGE>br1</BRIDGE><PUBLIC>0</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE></TEMPLATE></VNET><VNET><ID>1</ID><UID>2</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>A virtual network</NAME><TYPE>0</TYPE><BRIDGE>br0</BRIDGE><PUBLIC>1</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE><NETWORK_ADDRESS><![CDATA[192.168.0.0]]></NETWORK_ADDRESS><NETWORK_SIZE><![CDATA[C]]></NETWORK_SIZE></TEMPLATE></VNET></VNET_POOL>";
+    "<VNET_POOL><VNET><ID>0</ID><UID>1</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>Net number one</NAME><TYPE>1</TYPE><BRIDGE>br1</BRIDGE><PUBLIC>0</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE></TEMPLATE></VNET><VNET><ID>1</ID><UID>2</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>A virtual network</NAME><TYPE>0</TYPE><BRIDGE>br0</BRIDGE><RANGE><IP_START>192.168.0.1</IP_START><IP_END>192.168.0.254</IP_END></RANGE><PUBLIC>1</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE><NETWORK_MASK><![CDATA[255.255.255.0]]></NETWORK_MASK></TEMPLATE></VNET></VNET_POOL>";
 
 const string xml_dump_where =
-    "<VNET_POOL><VNET><ID>1</ID><UID>2</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>A virtual network</NAME><TYPE>0</TYPE><BRIDGE>br0</BRIDGE><PUBLIC>1</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE><NETWORK_ADDRESS><![CDATA[192.168.0.0]]></NETWORK_ADDRESS><NETWORK_SIZE><![CDATA[C]]></NETWORK_SIZE></TEMPLATE></VNET></VNET_POOL>";
+    "<VNET_POOL><VNET><ID>1</ID><UID>2</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>A virtual network</NAME><TYPE>0</TYPE><BRIDGE>br0</BRIDGE><RANGE><IP_START>192.168.0.1</IP_START><IP_END>192.168.0.254</IP_END></RANGE><PUBLIC>1</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE><NETWORK_MASK><![CDATA[255.255.255.0]]></NETWORK_MASK></TEMPLATE></VNET></VNET_POOL>";
 
 /* ************************************************************************* */
 /* ************************************************************************* */
@@ -411,16 +411,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 +428,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 +695,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 +708,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

From ee6888567a754a57b76837042b11094c748f41bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= <cmartins@fdi.ucm.es>
Date: Wed, 30 Nov 2011 11:41:41 +0100
Subject: [PATCH 10/15] Feature #602: Add tests for range definition

---
 src/vnm/test/VirtualNetworkPoolTest.cc | 130 +++++++++++++++++++++++++
 1 file changed, 130 insertions(+)

diff --git a/src/vnm/test/VirtualNetworkPoolTest.cc b/src/vnm/test/VirtualNetworkPoolTest.cc
index 556f6884a6..2a26cbef48 100644
--- a/src/vnm/test/VirtualNetworkPoolTest.cc
+++ b/src/vnm/test/VirtualNetworkPoolTest.cc
@@ -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:
@@ -1642,6 +1644,134 @@ public:
         CPPUNIT_ASSERT( rc != 0 );
         CPPUNIT_ASSERT( error_str != "" );
     }
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+    void range_definition()
+    {
+        VirtualNetworkPoolFriend * vnpool =
+                                static_cast<VirtualNetworkPoolFriend*>(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);
+        }
+    }
 };
 
 /* ************************************************************************* */

From a173e7bd754abc0b372aae76fb6267d4f5883ea5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= <cmartins@fdi.ucm.es>
Date: Wed, 30 Nov 2011 12:43:36 +0100
Subject: [PATCH 11/15] Feature #602: onevnet release returns error if a Lease
 is not used, this achieves the same behaviour for fixed and ranged networks

---
 src/vnm/Leases.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/vnm/Leases.cc b/src/vnm/Leases.cc
index c159294625..98cf0e38dc 100644
--- a/src/vnm/Leases.cc
+++ b/src/vnm/Leases.cc
@@ -490,7 +490,7 @@ int Leases::free_leases(vector<const Attribute*>&   vector_leases,
 
     it = leases.find(i_ip);
 
-    if ( it == leases.end() || (it->second->used && it->second->vid != -1) )
+    if ( it == leases.end() || !it->second->used || it->second->vid != -1 )
     {
         error_msg = "Lease is not on hold.";
         return -1;

From f0efbf09b6b36bfc7c1b9dd57e737fc908b02878 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= <cmartins@fdi.ucm.es>
Date: Wed, 30 Nov 2011 13:19:15 +0100
Subject: [PATCH 12/15] Feature #602: Add VNet hold and release methods in Java
 OCA

---
 .../client/vnet/VirtualNetwork.java           | 53 ++++++++++++++++++-
 src/oca/java/test/VirtualNetworkTest.java     | 48 +++++++++++++++++
 2 files changed, 100 insertions(+), 1 deletion(-)

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()
     {

From 536d69b5ab017f2a04facc865d810b5c6561e485 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= <cmartins@fdi.ucm.es>
Date: Thu, 1 Dec 2011 07:50:37 -0800
Subject: [PATCH 13/15] Feature #602: Change onevnet show format to separate
 used, free and 'on hold' leases

---
 src/cli/one_helper/onevnet_helper.rb | 18 ++++++++++++------
 src/oca/ruby/OpenNebula/XMLUtils.rb  |  4 ++--
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/src/cli/one_helper/onevnet_helper.rb b/src/cli/one_helper/onevnet_helper.rb
index 71ead0d55f..3a59dac76a 100644
--- a/src/cli/one_helper/onevnet_helper.rb
+++ b/src/cli/one_helper/onevnet_helper.rb
@@ -73,13 +73,19 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper
             puts str % ["IP_END", vn['RANGE/IP_END']]
         end
 
-        leases_str = vn.template_like_str('/VNET/LEASES', false)
+        lease_types = [ ["LEASES ON HOLD",  'LEASE[USED=1 and VID=-1]'],
+                        ["USED LEASES",     'LEASE[USED=1 and VID>-1]'],
+                        ["FREE LEASES",     'LEASE[USED=0]'] ]
 
-        if !leases_str.empty?
-            puts
-            CLIHelper.print_header(str_h1 % ["LEASES INFORMATION"], false)
-            puts leases_str
-        end
+        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/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?

From cdf1231f819814b3e98b5c5747dd34b78203846d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= <cmartins@fdi.ucm.es>
Date: Fri, 2 Dec 2011 12:23:21 +0100
Subject: [PATCH 14/15] Feature #602 #863: Add VLAN tag to vnets and VM NIC
 attribute

---
 include/VirtualNetwork.h               |  5 +++++
 src/cli/one_helper/onevnet_helper.rb   |  1 +
 src/vnm/VirtualNetwork.cc              | 29 ++++++++++++++++++++++----
 src/vnm/test/VirtualNetworkPoolTest.cc | 14 ++++++-------
 4 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/include/VirtualNetwork.h b/include/VirtualNetwork.h
index 6625c260b4..cca301be12 100644
--- a/include/VirtualNetwork.h
+++ b/include/VirtualNetwork.h
@@ -227,6 +227,11 @@ private:
      */
     string  vlan_id;
 
+    /**
+     *  Whether or not to isolate this network with the vnm driver
+     */
+    int     vlan;
+
     // -------------------------------------------------------------------------
     // Virtual Network Description
     // -------------------------------------------------------------------------
diff --git a/src/cli/one_helper/onevnet_helper.rb b/src/cli/one_helper/onevnet_helper.rb
index acaf71d0bb..561f49d97a 100644
--- a/src/cli/one_helper/onevnet_helper.rb
+++ b/src/cli/one_helper/onevnet_helper.rb
@@ -59,6 +59,7 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper
         puts str % ["PUBLIC", OpenNebulaHelper.boolean_to_str(vn['PUBLIC'])]
         puts str % ["TYPE", vn.type_str]
         puts str % ["BRIDGE", vn["BRIDGE"]]
+        puts str % ["VLAN", OpenNebulaHelper.boolean_to_str(vn['VLAN'])]
         puts str % ["PHYSICAL DEVICE", vn["PHYDEV"]] if vn["PHYDEV"]
         puts str % ["VLAN ID", vn["VLAN_ID"]] if vn["VLAN_ID"]
         puts str % ["USED LEASES", vn['TOTAL_LEASES']]
diff --git a/src/vnm/VirtualNetwork.cc b/src/vnm/VirtualNetwork.cc
index 5fa53f2115..0579f4d270 100644
--- a/src/vnm/VirtualNetwork.cc
+++ b/src/vnm/VirtualNetwork.cc
@@ -25,6 +25,8 @@
 
 #include "AuthManager.h"
 
+#define TO_UPPER(S) transform(S.begin(),S.end(),S.begin(),(int(*)(int))toupper)
+
 /* ************************************************************************** */
 /* Virtual Network :: Constructor/Destructor                                  */
 /* ************************************************************************** */
@@ -171,6 +173,7 @@ int VirtualNetwork::insert(SqlDB * db, string& error_str)
     int             rc;
 
     string          pub;
+    string          vlan_attr;
     string          s_type;
     string          ranged_error_str;
 
@@ -183,7 +186,7 @@ int VirtualNetwork::insert(SqlDB * db, string& error_str)
     // ------------ TYPE ----------------------
     erase_template_attribute("TYPE",s_type);
 
-    transform(s_type.begin(),s_type.end(),s_type.begin(),(int(*)(int))toupper);
+    TO_UPPER(s_type);
 
     if (s_type == "RANGED")
     {
@@ -219,6 +222,14 @@ int VirtualNetwork::insert(SqlDB * db, string& error_str)
 
     erase_template_attribute("VLAN_ID",vlan_id);
 
+    // ------------ VLAN ----------------------
+
+    erase_template_attribute("VLAN", vlan_attr);
+
+    TO_UPPER(vlan_attr);
+
+    vlan = (vlan_attr == "YES");
+
     // ------------ BRIDGE --------------------
 
     erase_template_attribute("BRIDGE",bridge);
@@ -236,7 +247,6 @@ int VirtualNetwork::insert(SqlDB * db, string& error_str)
             oss << "onebr" << oid;
  
             bridge = oss.str();
-            replace_template_attribute("BRIDGE",bridge);
         }
     }
 
@@ -244,7 +254,7 @@ int VirtualNetwork::insert(SqlDB * db, string& error_str)
 
     erase_template_attribute("PUBLIC", pub);
 
-    transform (pub.begin(), pub.end(), pub.begin(), (int(*)(int))toupper);
+    TO_UPPER(pub);
 
     public_obj = (pub == "YES");
 
@@ -456,7 +466,8 @@ string& VirtualNetwork::to_xml_extended(string& xml, bool extended) const
             "<GNAME>"  << gname  << "</GNAME>" <<
             "<NAME>"   << name   << "</NAME>"  <<
             "<TYPE>"   << type   << "</TYPE>"  <<
-            "<BRIDGE>" << bridge << "</BRIDGE>";
+            "<BRIDGE>" << bridge << "</BRIDGE>"<<
+            "<VLAN>"   << vlan   << "</VLAN>";
 
     if (!phydev.empty())
     {
@@ -522,6 +533,7 @@ int VirtualNetwork::from_xml(const string &xml_str)
     rc += xpath(int_type,   "/VNET/TYPE",   -1);
     rc += xpath(bridge,     "/VNET/BRIDGE", "not_found");
     rc += xpath(public_obj, "/VNET/PUBLIC", 0);
+    rc += xpath(vlan,       "/VNET/VLAN",   0);
     
     xpath(phydev,  "/VNET/PHYDEV", "");
     xpath(vlan_id, "/VNET/VLAN_ID","");
@@ -605,6 +617,15 @@ int VirtualNetwork::nic_attribute(VectorAttribute *nic, int vid)
     nic->replace("MAC"       ,mac);
     nic->replace("IP"        ,ip);
 
+    if ( vlan == 1 )
+    {
+        nic->replace("VLAN", "YES");
+    }
+    else
+    {
+        nic->replace("VLAN", "NO");
+    }
+
     if (!phydev.empty())
     {
         nic->replace("PHYDEV", phydev);
diff --git a/src/vnm/test/VirtualNetworkPoolTest.cc b/src/vnm/test/VirtualNetworkPoolTest.cc
index 2a26cbef48..d1744b2876 100644
--- a/src/vnm/test/VirtualNetworkPoolTest.cc
+++ b/src/vnm/test/VirtualNetworkPoolTest.cc
@@ -71,18 +71,18 @@ const string templates[] =
 
 const string xmls[] =
 {
-    "<VNET><ID>0</ID><UID>123</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>Net number one</NAME><TYPE>1</TYPE><BRIDGE>br1</BRIDGE><PUBLIC>0</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE></TEMPLATE><LEASES><LEASE><IP>130.10.0.1</IP><MAC>50:20:20:20:20:20</MAC><USED>0</USED><VID>-1</VID></LEASE></LEASES></VNET>",
+    "<VNET><ID>0</ID><UID>123</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>Net number one</NAME><TYPE>1</TYPE><BRIDGE>br1</BRIDGE><VLAN>0</VLAN><PUBLIC>0</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE></TEMPLATE><LEASES><LEASE><IP>130.10.0.1</IP><MAC>50:20:20:20:20:20</MAC><USED>0</USED><VID>-1</VID></LEASE></LEASES></VNET>",
 
-    "<VNET><ID>1</ID><UID>261</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>A virtual network</NAME><TYPE>0</TYPE><BRIDGE>br0</BRIDGE><RANGE><IP_START>192.168.0.1</IP_START><IP_END>192.168.0.254</IP_END></RANGE><PUBLIC>1</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE><NETWORK_MASK><![CDATA[255.255.255.0]]></NETWORK_MASK></TEMPLATE><LEASES></LEASES></VNET>",
+    "<VNET><ID>1</ID><UID>261</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>A virtual network</NAME><TYPE>0</TYPE><BRIDGE>br0</BRIDGE><VLAN>0</VLAN><RANGE><IP_START>192.168.0.1</IP_START><IP_END>192.168.0.254</IP_END></RANGE><PUBLIC>1</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE><NETWORK_MASK><![CDATA[255.255.255.0]]></NETWORK_MASK></TEMPLATE><LEASES></LEASES></VNET>",
 
-    "<VNET><ID>0</ID><UID>133</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>Net number two</NAME><TYPE>1</TYPE><BRIDGE>br1</BRIDGE><PUBLIC>0</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE></TEMPLATE><LEASES><LEASE><IP>130.10.2.1</IP><MAC>50:20:20:20:20:20</MAC><USED>0</USED><VID>-1</VID></LEASE></LEASES></VNET>",
+    "<VNET><ID>0</ID><UID>133</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>Net number two</NAME><TYPE>1</TYPE><BRIDGE>br1</BRIDGE><VLAN>0</VLAN><PUBLIC>0</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE></TEMPLATE><LEASES><LEASE><IP>130.10.2.1</IP><MAC>50:20:20:20:20:20</MAC><USED>0</USED><VID>-1</VID></LEASE></LEASES></VNET>",
 };
 
 const string xml_dump =
-    "<VNET_POOL><VNET><ID>0</ID><UID>1</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>Net number one</NAME><TYPE>1</TYPE><BRIDGE>br1</BRIDGE><PUBLIC>0</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE></TEMPLATE></VNET><VNET><ID>1</ID><UID>2</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>A virtual network</NAME><TYPE>0</TYPE><BRIDGE>br0</BRIDGE><RANGE><IP_START>192.168.0.1</IP_START><IP_END>192.168.0.254</IP_END></RANGE><PUBLIC>1</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE><NETWORK_MASK><![CDATA[255.255.255.0]]></NETWORK_MASK></TEMPLATE></VNET></VNET_POOL>";
+    "<VNET_POOL><VNET><ID>0</ID><UID>1</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>Net number one</NAME><TYPE>1</TYPE><BRIDGE>br1</BRIDGE><VLAN>0</VLAN><PUBLIC>0</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE></TEMPLATE></VNET><VNET><ID>1</ID><UID>2</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>A virtual network</NAME><TYPE>0</TYPE><BRIDGE>br0</BRIDGE><VLAN>0</VLAN><RANGE><IP_START>192.168.0.1</IP_START><IP_END>192.168.0.254</IP_END></RANGE><PUBLIC>1</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE><NETWORK_MASK><![CDATA[255.255.255.0]]></NETWORK_MASK></TEMPLATE></VNET></VNET_POOL>";
 
 const string xml_dump_where =
-    "<VNET_POOL><VNET><ID>1</ID><UID>2</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>A virtual network</NAME><TYPE>0</TYPE><BRIDGE>br0</BRIDGE><RANGE><IP_START>192.168.0.1</IP_START><IP_END>192.168.0.254</IP_END></RANGE><PUBLIC>1</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE><NETWORK_MASK><![CDATA[255.255.255.0]]></NETWORK_MASK></TEMPLATE></VNET></VNET_POOL>";
+    "<VNET_POOL><VNET><ID>1</ID><UID>2</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>A virtual network</NAME><TYPE>0</TYPE><BRIDGE>br0</BRIDGE><VLAN>0</VLAN><RANGE><IP_START>192.168.0.1</IP_START><IP_END>192.168.0.254</IP_END></RANGE><PUBLIC>1</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE><NETWORK_MASK><![CDATA[255.255.255.0]]></NETWORK_MASK></TEMPLATE></VNET></VNET_POOL>";
 
 /* ************************************************************************* */
 /* ************************************************************************* */
@@ -312,8 +312,8 @@ public:
             };
 
         string phydev_xml[] = {
-            "<VNET><ID>0</ID><UID>0</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>BRIDGE and PHYDEV</NAME><TYPE>1</TYPE><BRIDGE>br0</BRIDGE><PHYDEV>eth0</PHYDEV><PUBLIC>0</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE></TEMPLATE><LEASES><LEASE><IP>130.10.0.1</IP><MAC>50:20:20:20:20:20</MAC><USED>0</USED><VID>-1</VID></LEASE></LEASES></VNET>",
-            "<VNET><ID>1</ID><UID>0</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>No BRIDGE only PHYDEV</NAME><TYPE>1</TYPE><BRIDGE>onebr1</BRIDGE><PHYDEV>eth0</PHYDEV><PUBLIC>0</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE><BRIDGE><![CDATA[onebr1]]></BRIDGE></TEMPLATE><LEASES><LEASE><IP>130.10.0.1</IP><MAC>50:20:20:20:20:20</MAC><USED>0</USED><VID>-1</VID></LEASE></LEASES></VNET>"
+            "<VNET><ID>0</ID><UID>0</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>BRIDGE and PHYDEV</NAME><TYPE>1</TYPE><BRIDGE>br0</BRIDGE><VLAN>0</VLAN><PHYDEV>eth0</PHYDEV><PUBLIC>0</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE></TEMPLATE><LEASES><LEASE><IP>130.10.0.1</IP><MAC>50:20:20:20:20:20</MAC><USED>0</USED><VID>-1</VID></LEASE></LEASES></VNET>",
+            "<VNET><ID>1</ID><UID>0</UID><GID>0</GID><UNAME>the_user</UNAME><GNAME>oneadmin</GNAME><NAME>No BRIDGE only PHYDEV</NAME><TYPE>1</TYPE><BRIDGE>onebr1</BRIDGE><VLAN>0</VLAN><PHYDEV>eth0</PHYDEV><PUBLIC>0</PUBLIC><TOTAL_LEASES>0</TOTAL_LEASES><TEMPLATE></TEMPLATE><LEASES><LEASE><IP>130.10.0.1</IP><MAC>50:20:20:20:20:20</MAC><USED>0</USED><VID>-1</VID></LEASE></LEASES></VNET>"
         };
 
         // test vm with bridge and phydev

From ed564472f6f15e3151c118fc371f2144429b168b Mon Sep 17 00:00:00 2001
From: "Ruben S. Montero" <rubensm@dacya.ucm.es>
Date: Sun, 4 Dec 2011 19:44:50 +0100
Subject: [PATCH 15/15] feature #602: Moved size to get the default if needed

---
 src/vnm/RangedLeases.cc | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/vnm/RangedLeases.cc b/src/vnm/RangedLeases.cc
index d992ad29c0..0eea558afb 100644
--- a/src/vnm/RangedLeases.cc
+++ b/src/vnm/RangedLeases.cc
@@ -51,7 +51,6 @@ int RangedLeases::process_template(VirtualNetwork* vn,
     string st_ip_start  = "";
     string st_ip_end    = "";
 
-    unsigned int size = VirtualNetworkPool::default_size();
     unsigned int host_bits;
     unsigned int network_bits;
 
@@ -161,12 +160,18 @@ int RangedLeases::process_template(VirtualNetwork* vn,
             }
             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));
             }
@@ -178,6 +183,7 @@ int RangedLeases::process_template(VirtualNetwork* vn,
     // 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 )
@@ -190,8 +196,6 @@ int RangedLeases::process_template(VirtualNetwork* vn,
         goto error_not_base_addr;
     }
 
-    size = (1 << host_bits) - 2;
-
     // Set IP start/end
     if ( ip_start == 0 )
     {
@@ -200,7 +204,7 @@ int RangedLeases::process_template(VirtualNetwork* vn,
 
     if ( ip_end == 0 )
     {
-        ip_end   = net_addr + size;
+        ip_end   = net_addr +  (1 << host_bits) - 2;
     }
 
     // Check range restrictions