From 198ebfdefdb833111eccc9087fb8a53bb75643cb Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Fri, 2 May 2014 17:04:48 +0200 Subject: [PATCH] feature #2858: Implementation of Address Range class --- include/AddressRange.h | 206 +++++++++++++++ src/vnm/AddressRange.cc | 536 ++++++++++++++++++++++++++++++++++++++++ src/vnm/SConstruct | 1 + 3 files changed, 743 insertions(+) create mode 100644 include/AddressRange.h create mode 100644 src/vnm/AddressRange.cc diff --git a/include/AddressRange.h b/include/AddressRange.h new file mode 100644 index 0000000000..738497a4db --- /dev/null +++ b/include/AddressRange.h @@ -0,0 +1,206 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +#ifndef ADDRESS_RANGE_H_ +#define ADDRESS_RANGE_H_ + +#include +#include +#include + +using namespace std; + +class VectorAttribute; + +/** + * The Lease class represents an address lease from a Virtual Network. + */ +class AddressRange +{ +public: + + AddressRange(){}; + + virtual ~AddressRange(){}; + + /** + * Init an Address Range based on a vector attribute the following + * attributes will be parsed (* are optional): + * - TYPE = ETHER | IP4 | IP6 | IP4_6 + * - SIZE + * - MAC_START + * - IP_START + * - ULA_PREFIX + * - GLOBAL_PREFIX + * + * The following can be defined to override VNET values: + * - BRIDGE + * - VLAN + * - VLAN_ID + * - PHYDEV + * + * Any value defined in the INHERIT_VNET_ATTR can be defined as well. + * + * Any value for context can be included in the AR. + * + * Example: + * - AR = [ TYPE = "ETHER", SIZE = 128, MAC_START = "00:02:01:02:03:04"] + * - AR = [ TYPE = "ETHER", SIZE = 128] + * - AR = [ TYPE = IP4, + * SIZE = 256, + * IP_START = 10.0.0.0, + * DNS = 10.0.0.2] + * - AR = [ TYPE = "IP6", + * SIZE = 1024, + * ULA_PREFIX = "fd00:0:0:1::", + * GLOBAL_PREFIX = "2001::"] + */ + int init_address_range(VectorAttribute * attr, string& error_msg); + + /** + * Type of Addresses defined by this address range + */ + enum AddressType + { + ETHER = 0x00000001, /** MAC address type */ + IP4 = 0x00000003, /** IP version 4 address */ + IP6 = 0x00000005, /** IP version 6 address */ + IP4_6 = 0x00000007 /** IP dual stack version 4 & 6 addresses */ + }; + + /** + * Returns an unused address, which becomes used and fills a NIC attribute + * with the configuration parameters from the address range. + * + * @param nic the VM NIC attribute + * @return 0 if success + */ + int allocate_addr(VectorAttribute * nic, const vector &inherit); + + /** + * Frees a previous allocated address, referenced by its MAC address + * + * @param mac the MAC address in string form + */ + void free_addr(const string& mac); + + +private: + /* ---------------------------------------------------------------------- */ + /* String to binary conversion functions for different address types */ + /* ---------------------------------------------------------------------- */ + + /** + * MAC to binary (48 bits) + * @param mac in string form 00:02:01:02:03:04 + * @return 0 on success + */ + int mac_to_i(string mac, unsigned int i_mac[]); + + /** + * IP version 4 to binary (32 bits) + * @param ip in string form 192.168.0.2 + * @return 0 on success + */ + int ip_to_i(const string& _ip, unsigned int& i_ip); + + /** + * IPv6 64bits prefix conversion + * @param prefix in string form 2a00:1bc0:b001:A:: + * @return 0 on success + */ + int prefix6_to_i(const string& prefix, unsigned int ip[]); + + /* ---------------------------------------------------------------------- */ + /* NIC setup functions */ + /* ---------------------------------------------------------------------- */ + + void set_mac(unsigned int addr_index, VectorAttribute * nic); + + void set_ip(unsigned int addr_index, VectorAttribute * nic); + + void set_ip6(unsigned int addr_index, VectorAttribute * nic); + + void set_vnet(VectorAttribute *nic, const vector &inherit); + + /* ---------------------------------------------------------------------- */ + /* Address index set helper functions */ + /* ---------------------------------------------------------------------- */ + + void allocated_to_attr(); + + int attr_to_allocated(); + + void allocate_addr(unsigned int addr_index); + + void free_addr(unsigned int addr_index); + + /* ---------------------------------------------------------------------- */ + /* Address Range data */ + /* ---------------------------------------------------------------------- */ + + /** + * The type of addresses defined in the range + */ + AddressType type; + + /** + * Key-Value representation of the attribute + */ + VectorAttribute * attr; + + /** + * ID for this range, unique within the Virtual Network + */ + unsigned int id; + + /** + * Number of addresses in the range + */ + unsigned int size; + + /** + * First IP4 in the range + */ + unsigned int ip_start; + + /** + * First MAC in the range + */ + unsigned int mac_start[2]; + + /** + * Binary representation of the IPv6 address global unicast prefix + */ + unsigned int global6[2]; + + /** + * Binary representation of the IPv6 address site unicast prefix + */ + unsigned int ula6[2]; + + /** + * Next address to lease + */ + unsigned int next; + + /** + * Set of address leased to a VM or other VNET + */ + set allocated; +}; + +#endif diff --git a/src/vnm/AddressRange.cc b/src/vnm/AddressRange.cc new file mode 100644 index 0000000000..e584ef4dc0 --- /dev/null +++ b/src/vnm/AddressRange.cc @@ -0,0 +1,536 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +#include "AddressRange.h" +#include "Attribute.h" +#include "VirtualNetworkPool.h" + +#include + +using namespace std; + +int AddressRange::init_address_range(VectorAttribute * attr, string& error_msg) +{ + string value; + + /* ---------------------- Address Range type ---------------------------- */ + + value = attr->vector_value("TYPE"); + + if (value == "ETHER") + { + type = ETHER; + } + else if (value == "IP4") + { + type = IP4; + } + else if (value == "IP6") + { + type = IP6; + } + else if (value == "IP4_6") + { + type = IP4_6; + } + else + { + error_msg = "Unknown address range TYPE."; + return -1; + } + + /* ---------------------- Size and Attributes --------------------------- */ + + this->attr = attr; + + if ( attr->vector_value("SIZE", size) == -1 || size <= 0 ) + { + error_msg = "Wrong SIZE for address range"; + return -1; + } + + /* -------------------- MAC & IPv4 start addresses ---------------------- */ + + bool do_mac = false; + + value = attr->vector_value("MAC_START"); + + if (value.empty()) + { + do_mac = true; + mac_start[1] = VirtualNetworkPool::mac_prefix(); + } + else + { + if (mac_to_i(value, mac_start) == -1) + { + error_msg = "Wrong format for MAC_START attribute"; + return -1; + }; + } + + switch(type) + { + case ETHER: + case IP6: + if (do_mac) + { + srand(time(0)); + + mac_start[0] = rand() && 0x0000FFFF; + mac_start[0]+= (rand()<<16) && 0xFFFF0000; + } + break; + + case IP4: + case IP4_6: + value = attr->vector_value("IP_START"); + + if (value.empty() || ip_to_i(value, ip_start) == -1) + { + error_msg = "Wrong or empty IP_START attribute"; + return -1; + } + + if (do_mac) + { + mac_start[0] = ip_start; + } + break; + } + + /* -------------------------- IP6 prefixes ------------------------------ */ + + value = attr->vector_value("GLOBAL_PREFIX"); + + if (value.empty()) + { + global6[1]=global6[0]=0; + } + else if (prefix6_to_i(value, global6) != 0 ) + { + error_msg = "Wrong format for IP6 global address prefix"; + return -1; + } + + value = attr->vector_value("ULA_PREFIX"); + + if (value.empty()) + { + ula6[1]=ula6[0]=0; + } + else if (prefix6_to_i(value, ula6) != 0 ) + { + error_msg = "Wrong format for IP6 unique local address prefix"; + return -1; + } + + /* -------------------------- Internal ------------------------------ */ + + next = 0; + + if (attr_to_allocated() == -1) + { + error_msg = "Wrong format for ALLOCATED array"; + return -1; + } + + return 0; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +int AddressRange::mac_to_i(string mac, unsigned int i_mac[]) +{ + istringstream iss; + + size_t pos = 0; + int count = 0; + + unsigned int tmp; + + while ( (pos = mac.find(':')) != string::npos ) + { + mac.replace(pos,1," "); + count++; + } + + if (count != 5) + { + return -1; + } + + iss.str(mac); + + i_mac[1] = 0; + i_mac[0] = 0; + + iss >> hex >> i_mac[1] >> ws >> hex >> tmp >> ws; + i_mac[1] <<= 8; + i_mac[1] += tmp; + + for (int i=0;i<4;i++) + { + iss >> hex >> tmp >> ws; + + i_mac[0] <<= 8; + i_mac[0] += tmp; + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int AddressRange::ip_to_i(const string& _ip, unsigned int& i_ip) +{ + istringstream iss; + size_t pos=0; + int count = 0; + unsigned int tmp; + + string ip = _ip; + + while ( (pos = ip.find('.')) != string::npos ) + { + ip.replace(pos,1," "); + count++; + } + + if (count != 3) + { + return -1; + } + + iss.str(ip); + + i_ip = 0; + + for (int i=0;i<4;i++) + { + iss >> dec >> tmp >> ws; + + if ( tmp > 255 ) + { + return -1; + } + + i_ip <<= 8; + i_ip += tmp; + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int AddressRange::prefix6_to_i(const string& prefix, unsigned int ip[]) +{ + struct in6_addr s6; + + if (prefix.empty()) + { + ip[1] = ip[0] = 0; + return 0; + } + + int rc = inet_pton(AF_INET6, prefix.c_str(), &s6); + + if ( rc != 1 ) + { + return -1; + } + + ip[1] = ntohl(s6.s6_addr32[0]); + ip[0] = ntohl(s6.s6_addr32[1]); + + return 0; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +void AddressRange::set_mac(unsigned int addr_index, VectorAttribute * nic) +{ + ostringstream oss; + unsigned int temp_byte; + + for (int i=5;i>=0;i--) + { + if ( i < 4 ) + { + temp_byte = mac_start[0] + addr_index; + temp_byte >>= i*8; + } + else + { + temp_byte = mac_start[1]; + temp_byte >>= (i%4)*8; + } + + temp_byte &= 255; + + oss.width(2); + oss.fill('0'); + oss << hex << temp_byte; + + if(i!=0) + { + oss << ":"; + } + } + + nic->replace("MAC", oss.str()); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void AddressRange::set_ip(unsigned int addr_index, VectorAttribute * nic) +{ + ostringstream oss; + unsigned int temp_byte; + + for (int index=0;index<4;index++) + { + temp_byte = ip_start + addr_index; + temp_byte >>= (24-index*8); + temp_byte &= 255; + + oss << temp_byte; + + if(index!=3) + { + oss << "."; + } + } + + nic->replace("IP", oss.str()); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void AddressRange::set_ip6(unsigned int addr_index, VectorAttribute * nic) +{ + unsigned int eui64[2]; + unsigned int mlow = mac_start[0] + addr_index; + + struct in6_addr ip6; + char dst[INET6_ADDRSTRLEN]; + + eui64[1] = ((mac_start[1]+512)<<16) + ((mlow&0xFF000000)>>16) + 0x000000FF; + eui64[0] = 4261412864 + (mlow & 0x00FFFFFF); + + ip6.s6_addr32[2] = htonl(eui64[1]); + ip6.s6_addr32[3] = htonl(eui64[0]); + + /* Link Local */ + ip6.s6_addr32[0] = htonl(0xfe800000); + ip6.s6_addr32[1] = 0; + + if ( inet_ntop(AF_INET6, &ip6, dst, INET6_ADDRSTRLEN) != 0 ) + { + nic->replace("IP6_LINK", dst); + } + + if (ula6[1] != 0 || ula6[0] != 0 ) /* Unique Local Address*/ + { + ip6.s6_addr32[0] = htonl(ula6[1]); + ip6.s6_addr32[1] = htonl(ula6[0]); + + if ( inet_ntop(AF_INET6, &ip6, dst, INET6_ADDRSTRLEN) != 0 ) + { + nic->replace("IP6_ULA", dst); + } + } + + if (global6[1] != 0 || global6[0] != 0 ) /* Glocal Unicast*/ + { + ip6.s6_addr32[0] = htonl(global6[1]); + ip6.s6_addr32[1] = htonl(global6[0]); + + if ( inet_ntop(AF_INET6, &ip6, dst, INET6_ADDRSTRLEN) != 0 ) + { + nic->replace("IP6_GLOBAL", dst); + } + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void AddressRange::set_vnet(VectorAttribute *nic, const vector &inherit) +{ + string bridge = attr->vector_value("BRIDGE"); + string vlan = attr->vector_value("VLAN"); + string vlanid = attr->vector_value("VLAN_ID"); + string phydev = attr->vector_value("PHYDEV"); + + if (!bridge.empty()) + { + nic->replace("BRIDGE", bridge); + } + + if (!vlan.empty()) + { + nic->replace("VLAN", bridge); + } + + if (!phydev.empty()) + { + nic->replace("PHYDEV", phydev); + } + + if (!vlanid.empty()) + { + nic->replace("VLAN_ID", vlanid); + } + + vector::const_iterator it; + + for (it = inherit.begin(); it != inherit.end(); it++) + { + string inherit_val = attr->vector_value((*it).c_str()); + + if (!inherit_val.empty()) + { + nic->replace((*it).c_str(), inherit_val); + } + } +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +void AddressRange::allocated_to_attr() +{ + if (allocated.empty()) + { + attr->remove("ALLOCATED"); + return; + } + + set::const_iterator it; + + ostringstream oss; + + for (it = allocated.begin(); it != allocated.end(); it++) + { + oss << " " << (*it); + } + + attr->replace("ALLOCATED", oss.str()); +} + +/* -------------------------------------------------------------------------- */ + +int AddressRange::attr_to_allocated() +{ + string allocated_s = attr->vector_value("ALLOCATED"); + + if (allocated_s.empty()) + { + allocated.clear(); + return 0; + } + + istringstream iss(allocated_s); + unsigned int addr_index; + + while (!iss.eof()) + { + iss >> ws >> addr_index; + + if (!iss.fail()) + { + allocated.insert(addr_index); + return -1; + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +void AddressRange::allocate_addr(unsigned int addr_index) +{ + allocated.insert(addr_index); + + allocated_to_attr(); +} + +/* -------------------------------------------------------------------------- */ + +void AddressRange::free_addr(unsigned int addr_index) +{ + allocated.erase(addr_index); + + allocated_to_attr(); +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +int AddressRange::allocate_addr(VectorAttribute * nic, + const vector &inherit) +{ + int rc = -1; + + for ( unsigned int i=0; i= mac_start[0] ) + { + free_addr(mac_i[0] - mac_start[0]); + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/vnm/SConstruct b/src/vnm/SConstruct index 17ecc14a63..f3466b8e82 100644 --- a/src/vnm/SConstruct +++ b/src/vnm/SConstruct @@ -27,6 +27,7 @@ source_files=[ 'RangedLeases.cc', 'VirtualNetwork.cc', 'VirtualNetworkPool.cc', + 'AddressRange.cc' ] # Build library