1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-02-27 13:57:23 +03:00

F #911: IP(v6) alias(es) support

* Modify VM context generation.
   * Modify attach/detach nic functionality.
   * Modify CLI nic-attach, so an alias can be attached.

Co-authored-by: Alejandro Huertas <ahuertas@opennebula.systems>
This commit is contained in:
Ruben S. Montero 2018-12-04 14:41:55 +01:00
parent b89642aaab
commit ab1a05b69b
17 changed files with 825 additions and 224 deletions

View File

@ -78,6 +78,8 @@ public:
RETRY_ACTION = 43, // "one.vm.recover"
MONITOR_ACTION = 44, // internal, monitoring process
DISK_SNAPSHOT_RENAME_ACTION = 45, // "one.vm.disksnapshotrename"
ALIAS_ATTACH_ACTION = 46, // "one.vm.attachnic"
ALIAS_DETACH_ACTION = 47, // "one.vm.detachnic"
POFF_MIGRATE_ACTION = 48, // "one.vm.migrate"
POFF_HARD_MIGRATE_ACTION = 49 // "one.vm.migrate"
};

View File

@ -1440,6 +1440,26 @@ public:
return nic;
}
/**
* Deletes the alias of the NIC that was in the process of being attached/detached
*/
void delete_attach_alias(VirtualMachineNic *nic)
{
std::set<int> a_ids;
one_util::split_unique(nic->vector_value("ALIAS_IDS"), ',', a_ids);
for(std::set<int>::iterator it = a_ids.begin(); it != a_ids.end(); it++)
{
VirtualMachineNic * nic_a = nics.delete_nic(*it);
if ( nic_a != 0)
{
obj_template->remove(nic_a->vector_attribute());
}
}
}
// ------------------------------------------------------------------------
// Disk Snapshot related functions
// ------------------------------------------------------------------------
@ -1994,6 +2014,14 @@ private:
*/
void clear_nic_context(int nicid);
/**
* Deletes the NETWORK ALIAS related CONTEXT section for the given nic, i.e.
* ETH_<id>_ALIAS<aliasid>
* @param nicid the id of the NIC
* @param aliasid the idx of the ALIAS
*/
void clear_nic_alias_context(int nicid, int aliasidx);
/**
* Generate the PCI related CONTEXT setions, i.e. PCI_*. This function
* is also adds basic network attributes for pass-through NICs

View File

@ -101,6 +101,58 @@ public:
*/
void to_xml_short(std::ostringstream& oss) const;
/**
* Check is a nic is alias or not
*/
bool is_alias() const
{
return name() == "NIC_ALIAS";
}
/*
* Set nic NAME attribute if not empty, defaults to NAME = NIC${NIC_ID}
*/
std::string set_nic_name()
{
std::string name = vector_value("NAME");
if (!name.empty())
{
return name;
}
std::ostringstream oss;
oss << "NIC" << get_id();
replace("NAME", oss.str());
return oss.str();
}
/*
* Set nic alias NAME attribute defaults to NAME = NIC${PARENT_ID}_ALIAS${ALIAS_ID}
* @param parent_id for the alias
* @return alias name
*/
std::string set_nic_alias_name(int parent_id)
{
std::string name = vector_value("NAME");
if (!name.empty())
{
return name;
}
std::ostringstream oss;
oss << "NIC" << parent_id << "_" << "ALIAS" << get_id();
replace("NAME", oss.str());
return oss.str();
}
private:
/**
* Fills the authorization request for this NIC based on the VNET and SG
@ -133,11 +185,14 @@ public:
VirtualMachineAttributeSet(false)
{
std::vector<VectorAttribute *> vas;
std::vector<VectorAttribute *> alias;
std::vector<VectorAttribute *> pcis;
std::vector<VectorAttribute *>::iterator it;
tmpl->get(NIC_NAME, vas);
tmpl->get(NIC_ALIAS_NAME, alias);
tmpl->get("PCI", pcis);
for ( it=pcis.begin(); it != pcis.end() ; ++it)
@ -148,6 +203,11 @@ public:
}
}
for ( it=alias.begin(); it != alias.end(); ++it)
{
vas.push_back(*it);
}
init(vas, false);
};
@ -224,7 +284,7 @@ public:
/* NIC interface */
/* ---------------------------------------------------------------------- */
/**
* Returns the NIC attribute for a disk
* Returns the NIC attribute for a network interface
* @param nic_id of the NIC
* @return pointer to the attribute ir null if not found
*/
@ -233,6 +293,16 @@ public:
return static_cast<VirtualMachineNic *>(get_attribute(nic_id));
}
/**
* Deletes the NIC attribute from the VM NICs
* @param nic_id of the NIC
* @return pointer to the attribute or null if not found
*/
VirtualMachineNic * delete_nic(int nic_id)
{
return static_cast<VirtualMachineNic *>(get_attribute(nic_id));
}
/**
* Returns a set of the security group IDs in use in this set.
* @param sgs a set of security group IDs
@ -324,6 +394,8 @@ protected:
private:
static const char * NIC_NAME; //"NIC"
static const char * NIC_ALIAS_NAME; //"NIC_ALIAS"
static const char * NIC_ID_NAME; //"NIC_ID"
};

View File

@ -100,6 +100,21 @@
</xs:complexType>
</xs:element>
<xs:any minOccurs="0" maxOccurs="unbounded" processContents="skip"/>
<xs:element name="NIC_ALIAS" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="ALIAS_ID" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:any minOccurs="0" maxOccurs="unbounded" processContents="skip"/>
<xs:element name="PARENT" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="PARENT_ID" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:any minOccurs="0" maxOccurs="unbounded" processContents="skip"/>
<xs:element name="VCENTER_INSTANCE_ID" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="VCENTER_NET_REF" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="VCENTER_PORTGROUP_TYPE" type="xs:string" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:any minOccurs="0" maxOccurs="unbounded" processContents="skip"/>
</xs:sequence>
</xs:complexType>
</xs:element>
@ -184,6 +199,8 @@
RETRY_ACTION = 43
MONITOR_ACTION = 44
DISK_SNAPSHOT_RENAME_ACTION = 45
ALIAS_ATTACH_ACTION = 46
ALIAS_DETACH_ACTION = 47
-->
<xs:element name="ACTION" type="xs:integer"/>
<xs:element name="UID" type="xs:integer"/>

View File

@ -15,7 +15,6 @@
#--------------------------------------------------------------------------- #
require 'cli_helper'
require 'open3'
require 'io/console'

View File

@ -183,6 +183,21 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
:description => "Do the migrate by poweringoff hard the vm"
}
ALIAS = {
:name => "alias",
:short => "-a alias",
:large => "--alias alias",
:description=> "Attach the NIC as an ALIAS",
:format => String
}
NIC_NAME = {
:name => "nic_name",
:large => "--nic_name name",
:description=> "Name of the NIC",
:format => String
}
def self.rname
"VM"
end
@ -822,11 +837,12 @@ in the frontend machine.
extra_ips.uniq!
if vm.has_elements?("/VM/TEMPLATE/NIC") ||
['NIC', 'NIC_ALIAS'].each do |type|
if vm.has_elements?("/VM/TEMPLATE/#{type}") ||
vm.has_elements?("/VM/TEMPLATE/PCI[NIC_ID>-1]") || !extra_ips.empty?
puts
CLIHelper.print_header(str_h1 % "VM NICS",false)
CLIHelper.print_header(str_h1 % "VM #{type == 'NIC' ? 'NICS' : 'ALIAS'}",false)
nic_default = {"NETWORK" => "-",
"IP" => "-",
@ -836,8 +852,9 @@ in the frontend machine.
shown_ips = []
array_id = 0
vm_nics = [vm_hash['VM']['TEMPLATE']['NIC']]
vm_nics = [vm_hash['VM']['TEMPLATE'][type]]
if type == 'NIC'
vm_pcis = [vm_hash['VM']['TEMPLATE']['PCI']].flatten.compact
vm_pcis.each do |pci|
@ -845,6 +862,7 @@ in the frontend machine.
vm_nics << pci
end
end
end
vm_nics.flatten!
vm_nics.compact!
@ -935,6 +953,7 @@ in the frontend machine.
end
end
if type == 'NIC'
column :PCI_ID, "", :left, :size=>8 do |d|
if d["DOUBLE_ENTRY"]
""
@ -942,13 +961,15 @@ in the frontend machine.
d["PCI_ID"]
end
end
end
end.show(vm_nics,{})
while vm.has_elements?("/VM/TEMPLATE/NIC")
vm.delete_element("/VM/TEMPLATE/NIC")
while vm.has_elements?("/VM/TEMPLATE/#{type}")
vm.delete_element("/VM/TEMPLATE/#{type}")
end if !options[:all]
end
end
while vm.has_elements?("/VM/TEMPLATE/NIC")
vm.delete_element("/VM/TEMPLATE/NIC")

View File

@ -766,13 +766,17 @@ CommandParser::CmdParser.new(ARGV) do
Attaches a NIC to a running VM. When using --file add only one
NIC instance.
To attach a nic alias, use --file or --alias option.
States: RUNNING, POWEROFF
EOT
command :"nic-attach", nic_attach_desc, :vmid,
:options => [OneVMHelper::FILE,
OneVMHelper::NETWORK,
OneVMHelper::IP] do
OneVMHelper::IP,
OneVMHelper::ALIAS,
OneVMHelper::NIC_NAME] do
if options[:file].nil? && options[:network].nil?
STDERR.puts 'Provide a template file or a network:'
@ -786,10 +790,33 @@ CommandParser::CmdParser.new(ARGV) do
else
network_id = options[:network]
ip = options[:ip]
nic_alias = options[:alias]
nic_name = options[:nic_name]
if ip
if !nic_alias && !nic_name
template = "NIC = [ NETWORK_ID = #{network_id}, IP = #{ip} ]"
elsif !nic_alias && nic_name
template = "NIC = [ NETWORK_ID = #{network_id},
IP = #{ip},
NAME = #{nic_name} ]"
else
template = "NIC_ALIAS = \
[ NETWORK_ID = #{network_id},\
IP = #{ip},\
PARENT = #{nic_alias} ]"
end
else
if !nic_alias && !nic_name
template = "NIC = [ NETWORK_ID = #{network_id} ]"
elsif !nic_alias && nic_name
template = "NIC = [ NETWORK_ID = #{network_id},
NAME = #{nic_name} ]"
else
template = "NIC_ALIAS = \
[ NETWORK_ID = #{network_id},\
PARENT = #{nic_alias} ]"
end
end
end

View File

@ -1767,7 +1767,14 @@ int DispatchManager::attach_nic(int vid, VirtualMachineTemplate* tmpl,
vm->set_etime(the_time);
if ( tmpl->get("NIC") != 0 )
{
vm->set_action(History::NIC_ATTACH_ACTION, ra.uid, ra.gid, ra.req_id);
}
else
{
vm->set_action(History::ALIAS_ATTACH_ACTION, ra.uid, ra.gid, ra.req_id);
}
vmpool->update_history(vm);
@ -1858,7 +1865,14 @@ int DispatchManager::detach_nic(int vid, int nic_id,const RequestAttributes& ra,
vm->set_etime(the_time);
if ( !vm->get_nic(nic_id)->is_alias() )
{
vm->set_action(History::NIC_DETACH_ACTION, ra.uid, ra.gid, ra.req_id);
}
else
{
vm->set_action(History::ALIAS_DETACH_ACTION, ra.uid, ra.gid, ra.req_id);
}
vmpool->update_history(vm);

View File

@ -212,7 +212,9 @@ module OpenNebula
disk-snapshot-create disk-snapshot-delete terminate terminate-hard
disk-resize deploy chown chmod updateconf rename resize update
snapshot-resize snapshot-delete snapshot-revert disk-saveas
disk-snapshot-revert recover retry monitor disk-snapshot-rename 46 47 poff-migrt ph-migrt}
disk-snapshot-revert recover retry monitor disk-snapshot-rename
alias-attach alias-detach poweroff-migrate poweroff-hard-migrate
}
EXTERNAL_IP_ATTRS = [
'GUEST_IP',

View File

@ -16,6 +16,7 @@
#include "QuotaNetwork.h"
#include "Quotas.h"
#include "VirtualMachineNic.h"
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -30,23 +31,21 @@ const int QuotaNetwork::NUM_NET_METRICS = 1;
bool QuotaNetwork::check(PoolObjectSQL::ObjectType otype, Template * tmpl,
Quotas& default_quotas, string& error)
{
vector<VectorAttribute*> nic;
int num;
bool uses_lease;
map<string, float> net_request;
net_request.insert(make_pair("LEASES",1));
num = tmpl->get("NIC", nic);
VirtualMachineNics *nics = new VirtualMachineNics(tmpl);
VirtualMachineNics::NicIterator nic;
for (int i = 0 ; i < num ; i++)
for (nic = nics->begin() ; nic != nics->end() ; ++nic)
{
std::string net_mode = nic[i]->vector_value("NETWORK_MODE");
std::string net_mode = (*nic)->vector_value("NETWORK_MODE");
one_util::toupper(net_mode);
std::string net_id = nic[i]->vector_value("NETWORK_ID");
std::string net_id = (*nic)->vector_value("NETWORK_ID");
if ( net_mode == "AUTO" && net_id.empty() )
{
@ -57,18 +56,22 @@ bool QuotaNetwork::check(PoolObjectSQL::ObjectType otype, Template * tmpl,
if ( otype == PoolObjectSQL::VROUTER )
{
nic[i]->vector_value("FLOATING_IP", uses_lease);
(*nic)->vector_value("FLOATING_IP", uses_lease);
}
if ( !net_id.empty() && uses_lease )
{
if ( !check_quota(net_id, net_request, default_quotas, error) )
{
delete nics;
return false;
}
}
}
delete nics;
return true;
}
@ -77,28 +80,25 @@ bool QuotaNetwork::check(PoolObjectSQL::ObjectType otype, Template * tmpl,
void QuotaNetwork::del(PoolObjectSQL::ObjectType otype, Template * tmpl)
{
vector<VectorAttribute *> nic;
string net_id;
int num;
bool uses_lease;
map<string, float> net_request;
net_request.insert(make_pair("LEASES",1));
num = tmpl->get("NIC", nic);
VirtualMachineNics *nics = new VirtualMachineNics(tmpl);
VirtualMachineNics::NicIterator nic;
for (int i = 0 ; i < num ; i++)
for (nic = nics->begin() ; nic != nics->end() ; ++nic)
{
net_id = nic[i]->vector_value("NETWORK_ID");
net_id = (*nic)->vector_value("NETWORK_ID");
uses_lease = true;
if ( otype == PoolObjectSQL::VROUTER )
{
nic[i]->vector_value("FLOATING_IP", uses_lease);
(*nic)->vector_value("FLOATING_IP", uses_lease);
}
if (uses_lease)
@ -106,6 +106,8 @@ void QuotaNetwork::del(PoolObjectSQL::ObjectType otype, Template * tmpl)
del_quota(net_id, net_request);
}
}
delete nics;
}
/* -------------------------------------------------------------------------- */

View File

@ -512,6 +512,12 @@ string History::action_to_str(VMAction action)
case NIC_DETACH_ACTION:
st = "nic-detach";
break;
case ALIAS_ATTACH_ACTION:
st = "alias-attach";
break;
case ALIAS_DETACH_ACTION:
st = "alias-detach";
break;
case DISK_SNAPSHOT_CREATE_ACTION:
st = "disk-snapshot-create";
break;
@ -671,6 +677,14 @@ int History::action_from_str(const string& st, VMAction& action)
{
action = NIC_DETACH_ACTION;
}
else if (st == "alias-attach")
{
action = ALIAS_ATTACH_ACTION;
}
else if (st == "alias-detach")
{
action = ALIAS_DETACH_ACTION;
}
else if (st == "disk-snapshot-create")
{
action = DISK_SNAPSHOT_CREATE_ACTION;

View File

@ -2374,7 +2374,7 @@ int VirtualMachine::from_xml(const string &xml_str)
}
rc += obj_template->from_xml_node(content[0]);
vector<VectorAttribute *> vdisks, vnics, pcis;
vector<VectorAttribute *> vdisks, vnics, alias, pcis;
vector<VectorAttribute *>::iterator it;
obj_template->get("DISK", vdisks);
@ -2383,6 +2383,8 @@ int VirtualMachine::from_xml(const string &xml_str)
obj_template->get("NIC", vnics);
obj_template->get("NIC_ALIAS", alias);
obj_template->get("PCI", pcis);
for (it =pcis.begin(); it != pcis.end(); ++it)
@ -2393,6 +2395,11 @@ int VirtualMachine::from_xml(const string &xml_str)
}
}
for (it =alias.begin(); it != alias.end(); ++it)
{
vnics.push_back(*it);
}
nics.init(vnics, true);
ObjectXML::free_nodes(content);
@ -3265,9 +3272,11 @@ int VirtualMachine::get_network_leases(string& estr)
/* ---------------------------------------------------------------------- */
/* Get the NIC attributes: */
/* * NIC */
/* * NIC_ALIAS */
/* * PCI + TYPE = NIC */
/* ---------------------------------------------------------------------- */
vector<Attribute *> anics;
vector<Attribute *> alias;
user_obj_template->remove("NIC", anics);
@ -3285,6 +3294,23 @@ int VirtualMachine::get_network_leases(string& estr)
}
}
user_obj_template->remove("NIC_ALIAS", alias);
for (vector<Attribute*>::iterator it = alias.begin(); it != alias.end(); )
{
if ( (*it)->type() != Attribute::VECTOR )
{
delete *it;
it = alias.erase(it);
}
else
{
obj_template->set(*it);
anics.push_back(*it);
++it;
}
}
vector<VectorAttribute *> pcis;
vector<VectorAttribute *>::iterator it;
@ -3331,9 +3357,14 @@ int VirtualMachine::set_up_attach_nic(VirtualMachineTemplate * tmpl, string& err
if ( new_nic == 0 )
{
err = "Wrong format or missing NIC attribute";
new_nic = tmpl->get("NIC_ALIAS");
if ( new_nic == 0 )
{
err = "Wrong format or missing NIC/NIC_ALIAS attribute";
return -1;
}
}
new_nic = new_nic->clone();
@ -3373,6 +3404,10 @@ int VirtualMachine::set_up_attach_nic(VirtualMachineTemplate * tmpl, string& err
int VirtualMachine::set_detach_nic(int nic_id)
{
std::set<int> a_ids;
int parent_id, alias_id;
VirtualMachineNic * nic = nics.get_nic(nic_id);
if ( nic == 0 )
@ -3382,8 +3417,73 @@ int VirtualMachine::set_detach_nic(int nic_id)
nic->set_attach();
/*------------------------------------------------------------------------*/
/* Clear context of the NIC or NIC_ALIAS */
/* 1. NIC with alias will also clear context for the NIC_ALIAS */
/* 2. NIC_ALIAS will update the ALIAS_IDs list */
/*------------------------------------------------------------------------*/
if ( !nic->is_alias() )
{
clear_nic_context(nic_id);
one_util::split_unique(nic->vector_value("ALIAS_IDS"), ',', a_ids);
for(std::set<int>::iterator it = a_ids.begin(); it != a_ids.end(); ++it)
{
VirtualMachineNic *alias = nics.get_nic(*it);
if ( alias == 0 )
{
continue;
}
if ( alias->vector_value("ALIAS_ID", alias_id) != 0 )
{
continue;
}
clear_nic_alias_context(nic_id, alias_id);
}
}
else
{
std::ostringstream oss;
if ( nic->vector_value("ALIAS_ID", alias_id) != 0 ||
nic->vector_value("PARENT_ID", parent_id) != 0 )
{
return -1;
}
clear_nic_alias_context(parent_id, alias_id);
nic = nics.get_nic(parent_id);
if ( nic == 0 )
{
return -1;
}
one_util::split_unique(nic->vector_value("ALIAS_IDS"), ',', a_ids);
for(std::set<int>::iterator it = a_ids.begin(); it != a_ids.end(); ++it)
{
if ( *it == nic_id )
{
continue;
}
if ( !oss.str().empty() )
{
oss << ",";
}
oss << *it;
}
nic->replace("ALIAS_IDS", oss.str());
}
return 0;
}

View File

@ -61,7 +61,8 @@ const std::vector<ContextVariable> NETWORK_CONTEXT = {
{"MTU", "GUEST_MTU", "", true},
{"VLAN_ID", "VLAN_ID", "", true},
{"VROUTER_IP", "VROUTER_IP", "", false},
{"VROUTER_MANAGEMENT", "VROUTER_MANAGEMENT", "", false}
{"VROUTER_MANAGEMENT", "VROUTER_MANAGEMENT", "", false},
{"EXTERNAL", "EXTERNAL", "", false},
};
const std::vector<ContextVariable> NETWORK6_CONTEXT = {
@ -71,6 +72,7 @@ const std::vector<ContextVariable> NETWORK6_CONTEXT = {
{"CONTEXT_FORCE_IPV4", "CONTEXT_FORCE_IPV4", "", true},
{"IP6_PREFIX_LENGTH", "PREFIX_LENGTH", "", true},
{"VROUTER_IP6", "VROUTER_IP6_GLOBAL", "VROUTER_IP6", false},
{"EXTERNAL", "EXTERNAL", "", false},
};
/* -------------------------------------------------------------------------- */
@ -251,6 +253,9 @@ static void parse_context_network(const std::vector<ContextVariable>& cvars,
{
string nic_id = nic->vector_value("NIC_ID");
string alias_id = nic->vector_value("ALIAS_ID");
string parent_id = nic->vector_value("PARENT_ID");
std::vector<ContextVariable>::const_iterator it;
for (it = cvars.begin(); it != cvars.end() ; ++it)
@ -258,7 +263,15 @@ static void parse_context_network(const std::vector<ContextVariable>& cvars,
ostringstream cvar;
string cval;
if (nic->name() == "NIC")
{
cvar << "ETH" << nic_id << "_" << (*it).context_name;
}
else
{
cvar << "ETH" << parent_id << "_ALIAS" << alias_id << "_"
<< (*it).context_name;
}
cval = nic->vector_value((*it).nic_name); //Check the NIC
@ -300,6 +313,7 @@ int VirtualMachine::generate_network_context(VectorAttribute* context,
}
vector<VectorAttribute *> vatts;
vector<VectorAttribute *> aatts;
int rc;
string parsed;
@ -308,13 +322,17 @@ int VirtualMachine::generate_network_context(VectorAttribute* context,
VectorAttribute tmp_context("TMP_CONTEXT");
int num_vatts = obj_template->get("NIC", vatts);
int num_aatts = obj_template->get("NIC_ALIAS", aatts);
int num_tatts = num_vatts + num_aatts;
if ( num_vatts == 0 )
if ( num_tatts == 0 )
{
return 0;
}
for(int i=0; i<num_vatts; i++)
vatts.insert(vatts.end(), aatts.begin(), aatts.end());
for(int i=0; i<num_tatts; i++)
{
std::string net_mode = vatts[i]->vector_value("NETWORK_MODE");
one_util::toupper(net_mode);
@ -673,3 +691,37 @@ void VirtualMachine::clear_nic_context(int nicid)
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
static void clear_context_alias_network(const std::vector<ContextVariable>& cvars,
VectorAttribute * context, int nic_id, int alias_id)
{
ostringstream att_name;
std::vector<ContextVariable>::const_iterator it;
for (it = cvars.begin(); it != cvars.end() ; ++it)
{
att_name.str("");
att_name << "ETH" << nic_id << "_ALIAS" << alias_id << "_"
<< (*it).context_name;
context->remove(att_name.str());
}
}
/* -------------------------------------------------------------------------- */
void VirtualMachine::clear_nic_alias_context(int nicid, int aliasidx)
{
VectorAttribute * context = obj_template->get("CONTEXT");
if (context == 0)
{
return;
}
clear_context_alias_network(NETWORK_CONTEXT, context, nicid, aliasidx);
clear_context_alias_network(NETWORK6_CONTEXT, context, nicid, aliasidx);
}
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

View File

@ -236,10 +236,21 @@ void VirtualMachineNic::to_xml_short(std::ostringstream& oss) const
const char * VirtualMachineNics::NIC_NAME = "NIC";
const char * VirtualMachineNics::NIC_ALIAS_NAME = "NIC_ALIAS";
const char * VirtualMachineNics::NIC_ID_NAME = "NIC_ID";
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
struct NicAliasID
{
NicAliasID(int _n):nic_id(_n), alias_id(0){};
int nic_id;
int alias_id;
std::string alias_id_s;
};
int VirtualMachineNics::get_network_leases(int vm_id, int uid,
vector<Attribute *> nics, VectorAttribute * nic_default,
@ -252,20 +263,27 @@ int VirtualMachineNics::get_network_leases(int vm_id, int uid,
set<int> sg_ids;
vector<Attribute*>::iterator it;
vector<Attribute*>::iterator it, it_a;
int nic_id;
vector<Attribute *> alias_nics;
std::map<std::string, NicAliasID> nic_map;
/* ---------------------------------------------------------------------- */
/* Get the interface network information */
/* ---------------------------------------------------------------------- */
for (it=nics.begin(), nic_id=0 ; it != nics.end() ; ++it, ++nic_id)
for (it=nics.begin(), nic_id=0 ; it != nics.end() ; ++it)
{
VectorAttribute * vnic = static_cast<VectorAttribute *>(*it);
VirtualMachineNic * nic = new VirtualMachineNic(vnic, nic_id);
std::string net_mode = vnic->vector_value("NETWORK_MODE");
one_util::toupper(net_mode);
if (vnic->name() == "NIC")
{
VirtualMachineNic * nic = new VirtualMachineNic(vnic, nic_id);
if (net_mode != "AUTO" )
{
if ( nic_default != 0 )
@ -276,18 +294,113 @@ int VirtualMachineNics::get_network_leases(int vm_id, int uid,
if ( vnpool->nic_attribute(PoolObjectSQL::VM, nic, nic_id, uid,
vm_id, error_str) == -1 )
{
delete nic;
return -1;
}
nic->get_security_groups(sg_ids);
std::string nic_name = nic->set_nic_name();
NicAliasID na(nic_id);
nic_map.insert(std::make_pair(nic_name, na));
}
else
{
nic->replace("NIC_ID", nic_id);
}
nic_id++;
add_attribute(nic, nic->get_nic_id());
}
else if (net_mode == "AUTO")
{
error_str = "Alias is incompatible with auto mode";
return -1;
}
else
{
alias_nics.push_back(vnic);
}
}
/* ---------------------------------------------------------------------- */
/* Check NIC vs NIC_ALIAS mapping consistency */
/* Sets: */
/* - PARENT_ID (the id of the parent NIC) */
/* - ALIAS_ID (id of the alias) */
/* - NIC_ID */
/* - NIC attributes (IP, MAC,...) */
/* ---------------------------------------------------------------------- */
for (it=alias_nics.begin(); it != alias_nics.end() ; ++it, ++nic_id)
{
std::map<std::string, NicAliasID>::iterator nit;
VirtualMachineNic * nic = new
VirtualMachineNic(static_cast<VectorAttribute *>(*it), nic_id);
std::string pnic = nic->vector_value("PARENT");
nit = nic_map.find(pnic);
if ( nit == nic_map.end() )
{
error_str = "NIC named " + pnic + " not found for alias";
delete nic;
return -1;
}
nic->replace("PARENT_ID", nit->second.nic_id);
nic->replace("ALIAS_ID", nit->second.alias_id);
if (!nit->second.alias_id_s.empty())
{
nit->second.alias_id_s += ",";
}
nit->second.alias_id_s += std::to_string(nic_id);
nit->second.alias_id++;
nic->replace("NIC_ID", nic_id);
if ( vnpool->nic_attribute(PoolObjectSQL::VM, nic, nic_id, uid,
vm_id, error_str) == -1 )
{
delete nic;
return -1;
}
nic->set_nic_alias_name(nit->second.nic_id);
add_attribute(nic, nic->get_nic_id());
}
/* ---------------------------------------------------------------------- */
/* Set the ALIAS ids on the parent interfaces */
/* ---------------------------------------------------------------------- */
for (it=nics.begin(); it != nics.end() ; ++it)
{
std::map<std::string, NicAliasID>::iterator nit;
VectorAttribute * vnic = static_cast<VectorAttribute *>(*it);
std::string nic_name = vnic->vector_value("NAME");
nit = nic_map.find(nic_name);
if ( nit == nic_map.end() || nit->second.alias_id_s.empty())
{
continue;
}
vnic->replace("ALIAS_IDS", nit->second.alias_id_s);
}
/* ---------------------------------------------------------------------- */
/* Get the secutiry groups */
@ -399,6 +512,60 @@ int VirtualMachineNics::set_up_attach_nic(int vmid, int uid, int cluster_id,
}
VirtualMachineNic * nic = new VirtualMachineNic(vnic, max_nic_id + 1);
VirtualMachineNic * pnic = 0;
std::string alias_ids;
if ( nic->is_alias() )
{
int pid, alias_id;
for(nic_iterator it = begin(); it != end() ; ++it)
{
if ( (*it)->vector_value("NAME") == nic->vector_value("PARENT") )
{
std::set<int> a_ids;
pnic = *it;
pid = pnic->get_nic_id();
pnic->vector_value("ALIAS_IDS", alias_ids);
if (alias_ids.empty())
{
alias_id = 0;
}
else
{
one_util::split_unique(alias_ids, ',', a_ids);
alias_id = *(a_ids.rbegin()) + 1;
alias_ids += ",";
}
alias_ids += std::to_string(max_nic_id + 1);
break;
}
}
if ( pnic == 0 )
{
error_str = "Alias not found.";
return -1;
}
nic->set_nic_alias_name(pid);
nic->replace("PARENT_ID", pid);
nic->replace("ALIAS_ID", alias_id);
}
else
{
nic->set_nic_name();
}
if ( nic_default != 0 )
{
@ -450,6 +617,8 @@ int VirtualMachineNics::set_up_attach_nic(int vmid, int uid, int cluster_id,
// -------------------------------------------------------------------------
// Get security groups for the new nic
// -------------------------------------------------------------------------
if ( !nic->is_alias() )
{
set<int> nic_sgs, vm_sgs;
get_security_groups(vm_sgs);
@ -462,12 +631,18 @@ int VirtualMachineNics::set_up_attach_nic(int vmid, int uid, int cluster_id,
}
sgpool->get_security_group_rules(vmid, nic_sgs, sgs);
}
// -------------------------------------------------------------------------
// Add the nic to the set
// -------------------------------------------------------------------------
add_attribute(nic, nic->get_nic_id());
if ( pnic != 0 )
{
pnic->replace("ALIAS_IDS", alias_ids);
}
return 0;
}

View File

@ -1144,12 +1144,25 @@ void VirtualMachinePool::delete_hotplug_nic(int vid, bool attach)
}
}
std::set<int> a_ids;
one_util::split_unique(nic->vector_value("ALIAS_IDS"), ',', a_ids);
for(std::set<int>::iterator it = a_ids.begin(); it != a_ids.end(); ++it)
{
tmpl.set(vm->get_nic(*it)->vector_attribute()->clone());
vm->get_nic(*it)->release_network_leases(oid);
}
nic->release_network_leases(oid);
vm->delete_attach_alias(nic);
update(vm);
vm->unlock();
nic->release_network_leases(oid);
tmpl.set(nic->vector_attribute());
Quotas::quota_del(Quotas::NETWORK, uid, gid, &tmpl);

View File

@ -169,14 +169,16 @@ class VmmAction
end
end
vm_template_xml.elements.each("TEMPLATE/NIC") do |element|
["NIC", "NIC_ALIAS"].each do |r|
vm_template_xml.elements.each("TEMPLATE/#{r}") do |element|
vn_mad = element.get_text("VN_MAD").to_s
next if vn_mad.empty?
vnm_drivers << vn_mad unless vnm_drivers.include?(vn_mad)
add_element_to_path(vm_vnm_xml, element, "TEMPLATE/NIC")
add_element_to_path(vm_vnm_xml, element, "TEMPLATE/#{r}")
end
end
return [vnm_drivers, vm_vnm_xml]
@ -902,11 +904,23 @@ class ExecDriver < VirtualMachineDriver
target_device = xml_data.elements['VM/TEMPLATE/CONTEXT/TARGET']
target_device = target_device.text if target_device
nic_alias = false
external = false
if xml_data.elements["VM/TEMPLATE/NIC[ATTACH='YES']"]
base_tmpl = "VM/TEMPLATE/NIC[ATTACH='YES']"
else
base_tmpl = "VM/TEMPLATE/NIC_ALIAS[ATTACH='YES']"
nic_alias = true
end
external = true if xml_data.elements["#{base_tmpl}/EXTERNAL"]
begin
source = xml_data.elements["VM/TEMPLATE/NIC[ATTACH='YES']/BRIDGE"]
mac = xml_data.elements["VM/TEMPLATE/NIC[ATTACH='YES']/MAC"]
target = xml_data.elements["VM/TEMPLATE/NIC[ATTACH='YES']/TARGET"]
vn_mad = xml_data.elements["VM/TEMPLATE/NIC[ATTACH='YES']/VN_MAD"]
source = xml_data.elements["#{base_tmpl}/BRIDGE"]
mac = xml_data.elements["#{base_tmpl}/MAC"]
target = xml_data.elements["#{base_tmpl}/TARGET"]
vn_mad = xml_data.elements["#{base_tmpl}/VN_MAD"]
source = source.text.strip
mac = mac.text.strip
@ -918,7 +932,7 @@ class ExecDriver < VirtualMachineDriver
return
end
model = xml_data.elements["VM/TEMPLATE/NIC[ATTACH='YES']/MODEL"]
model = xml_data.elements["#{base_tmpl}/MODEL"]
model = model.text if !model.nil?
model = model.strip if !model.nil?
@ -926,6 +940,7 @@ class ExecDriver < VirtualMachineDriver
action = VmmAction.new(self, id, :attach_nic, drv_message)
if !nic_alias
steps=[
# Execute pre-attach networking setup
{
@ -950,13 +965,31 @@ class ExecDriver < VirtualMachineDriver
:parameters => [:deploy_id, mac]
}
]
},
}
]
elsif nic_alias && external
steps=[
# Execute pre-attach networking setup
{
:driver => :vnm,
:action => :pre
},
# Execute post-boot networking setup
{
:driver => :vnm,
:action => :post,
:parameters => [:deploy_id]
}
]
else
steps = []
end
steps << {
:driver => :vmm,
:action => :prereconfigure,
:parameters => [:deploy_id, target_device]
}
]
if tm_command && !tm_command.empty?
steps << {
@ -981,8 +1014,20 @@ class ExecDriver < VirtualMachineDriver
def detach_nic(id, drv_message)
xml_data = decode(drv_message)
nic_alias = false
external = false
if xml_data.elements["VM/TEMPLATE/NIC[ATTACH='YES']"]
base_tmpl = "VM/TEMPLATE/NIC[ATTACH='YES']"
else
base_tmpl = "VM/TEMPLATE/NIC_ALIAS[ATTACH='YES']"
nic_alias = true
end
external = true if xml_data.elements["#{base_tmpl}/EXTERNAL"]
begin
mac = xml_data.elements["VM/TEMPLATE/NIC[ATTACH='YES']/MAC"]
mac = xml_data.elements["#{base_tmpl}/MAC"]
mac = mac.text.strip
rescue
send_message(action, RESULT[:failure], id,
@ -992,6 +1037,7 @@ class ExecDriver < VirtualMachineDriver
action = VmmAction.new(self, id, :detach_nic, drv_message)
if !nic_alias
steps=[
# Detach the NIC
{
@ -1005,6 +1051,17 @@ class ExecDriver < VirtualMachineDriver
:action => :clean
}
]
elsif nic_alias && external
steps=[
# Clean networking setup
{
:driver => :vnm,
:action => :clean
}
]
else
steps = []
end
action.run(steps)
end

View File

@ -614,6 +614,12 @@ VectorAttribute * VirtualRouter::attach_nic(
nics.clear();
if ( tmpl->get("NIC_ALIAS") != 0 )
{
error_str = "Alias can't be attached to virtual router.";
return 0;
}
if ( tmpl->get("NIC", nics) != 1 )
{
error_str = "The template must contain one NIC attribute";