1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-06 12:58:18 +03:00

Merge branch 'feature-4620'

This commit is contained in:
Ruben S. Montero 2016-07-18 19:04:54 +02:00
commit ed745428c4
24 changed files with 871 additions and 252 deletions

View File

@ -117,6 +117,19 @@ public:
static int get_pci_value(const char * name,
const VectorAttribute * pci_device,
unsigned int& value);
/**
* Sets the PCI device address in the Virtual Machine as follows;
* - VM_DOMAIN: 0x0000
* - VM_BUS: dbus or VM_BUS in PCI attribute
* - VM_SLOT: PCI_ID + 1
* - VM_FUNCTION: 0
* - VM_ADDRESS: BUS:SLOT.0
* @param pci_device to set the address in
* @param default_bus if not set in PCI attribute (PCI_PASSTHROUGH_BUS
* in oned.conf)
* @return -1 if wrong bus 0 on success
*/
static int set_pci_address(VectorAttribute * pci_device, const string& dbus);
private:
/**

View File

@ -1249,10 +1249,16 @@ public:
static int release_network_leases(const VectorAttribute * nic, int vmid);
/**
* Returns a set of the security group IDs in use in this VM
* Returns a set of the security group IDs in use in this VM. VirtualMachine
* and static version.
* @param sgs a set of security group IDs
*/
void get_security_groups(set<int>& sgs) const;
void get_security_groups(set<int>& sgs) const
{
get_security_groups(static_cast<VirtualMachineTemplate *>(obj_template), sgs);
}
static void get_security_groups(VirtualMachineTemplate *tmpl, set<int>& sgs);
/**
* Remove the rules associated to the given security group rules
@ -1922,6 +1928,14 @@ private:
*/
bool generate_network_context(VectorAttribute * context);
/**
* Generate the PCI related CONTEXT setions, i.e. PCI_*. This function
* is also adds basic network attributes for pass-through NICs
* @param context attribute of the VM
* @return true if the net context was generated.
*/
bool generate_pci_context(VectorAttribute * context);
/**
* Generate the ONE_GATE token & url
* @param context attribute of the VM

View File

@ -199,6 +199,10 @@ DEFAULT_COST = [
# for vxlan networks.
# start: First VNI to use
# NOTE: reserved is not supported by this pool
#
# PCI_PASSTHROUGH_BUS: Default bus to attach passthrough devices in the guest,
# in hex notation. It may be overwritten in the PCI device using the BUS
# attribute.
#*******************************************************************************
NETWORK_SIZE = 254
@ -214,6 +218,8 @@ VXLAN_IDS = [
START = "2"
]
#PCI_PASSTHROUGH_BUS = "0x01"
#*******************************************************************************
# DataStore Configuration
#*******************************************************************************

View File

@ -164,6 +164,10 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
vm_nics = [vm["TEMPLATE"]['NIC']].flatten
end
if !vm["TEMPLATE"]["PCI"].nil?
vm_nics = [vm_nics, vm["TEMPLATE"]['PCI']].flatten
end
vm_nics.each do |nic|
["IP", "IP6_GLOBAL", "IP6_ULA",
"VROUTER_IP", "VROUTER_IP6_GLOBAL", "VROUTER_IP6_ULA"].each do |attr|
@ -468,6 +472,8 @@ in the frontend machine.
cluster = nil
vm_hash = vm.to_hash
if %w{ACTIVE SUSPENDED POWEROFF}.include? vm.state_str
cluster_id = vm['/VM/HISTORY_RECORDS/HISTORY[last()]/CID']
else
@ -515,7 +521,7 @@ in the frontend machine.
CLIHelper.print_header(str_h1 % "VIRTUAL MACHINE MONITORING",false)
vm_monitoring = vm.to_hash['VM']['MONITORING']
vm_monitoring = vm_hash['VM']['MONITORING']
# Find out if it is a hybrid VM to avoid showing local IPs
isHybrid=false
@ -569,11 +575,11 @@ in the frontend machine.
vm_disks = []
if vm.has_elements?("/VM/TEMPLATE/DISK")
vm_disks = [vm.to_hash['VM']['TEMPLATE']['DISK']].flatten
vm_disks = [vm_hash['VM']['TEMPLATE']['DISK']].flatten
end
if vm.has_elements?("/VM/TEMPLATE/CONTEXT")
context_disk = vm.to_hash['VM']['TEMPLATE']['CONTEXT']
context_disk = vm_hash['VM']['TEMPLATE']['CONTEXT']
context_disk["IMAGE"] = "CONTEXT"
context_disk["DATASTORE"] = "-"
@ -682,16 +688,21 @@ in the frontend machine.
sg_nics = []
if (vm.has_elements?("/VM/TEMPLATE/NIC/SECURITY_GROUPS"))
sg_nics = [vm.to_hash['VM']['TEMPLATE']['NIC']].flatten
if (vm.has_elements?("/VM/TEMPLATE/NIC/SECURITY_GROUPS") ||
vm.has_elements?("/VM/TEMPLATE/PCI[NIC_ID>-1]/SECURITY_GROUPS"))
sg_nics.each do |nic|
sg = nic["SECURITY_GROUPS"]
sg_nics = [vm_hash['VM']['TEMPLATE']['NIC']]
if sg.nil?
next
sg_pcis = [vm_hash['VM']['TEMPLATE']['PCI']].flatten.compact
sg_pcis.each do |pci|
if !pci['NIC_ID'].nil?
sg_nics << pci
end
end
sg_nics.flatten!
sg_nics.compact!
end
# This variable holds the extra IP's got from monitoring. Right
@ -710,7 +721,9 @@ in the frontend machine.
extra_ips.uniq!
if vm.has_elements?("/VM/TEMPLATE/NIC") || !extra_ips.empty?
if vm.has_elements?("/VM/TEMPLATE/NIC") ||
vm.has_elements?("/VM/TEMPLATE/PCI[NIC_ID>-1]") || !extra_ips.empty?
puts
CLIHelper.print_header(str_h1 % "VM NICS",false)
@ -722,7 +735,19 @@ in the frontend machine.
shown_ips = []
array_id = 0
vm_nics = [vm.to_hash['VM']['TEMPLATE']['NIC']].flatten.compact
vm_nics = [vm_hash['VM']['TEMPLATE']['NIC']]
vm_pcis = [vm_hash['VM']['TEMPLATE']['PCI']].flatten.compact
vm_pcis.each do |pci|
if !pci['NIC_ID'].nil?
vm_nics << pci
end
end
vm_nics.flatten!
vm_nics.compact!
vm_nics.each {|nic|
next if nic.has_key?("CLI_DONE")
@ -809,6 +834,14 @@ in the frontend machine.
end
end
column :PCI_ID, "", :left, :size=>8 do |d|
if d["DOUBLE_ENTRY"]
""
else
d["PCI_ID"]
end
end
end.show(vm_nics,{})
while vm.has_elements?("/VM/TEMPLATE/NIC")
@ -891,7 +924,7 @@ in the frontend machine.
d["RANGE"]
end
end.show([vm.to_hash['VM']['TEMPLATE']['SECURITY_GROUP_RULE']].flatten, {})
end.show([vm_hash['VM']['TEMPLATE']['SECURITY_GROUP_RULE']].flatten, {})
while vm.has_elements?("/VM/TEMPLATE/SECURITY_GROUP_RULE")
vm.delete_element("/VM/TEMPLATE/SECURITY_GROUP_RULE")
@ -920,7 +953,7 @@ in the frontend machine.
d["HYPERVISOR_ID"] if !d.nil?
end
end.show([vm.to_hash['VM']['TEMPLATE']['SNAPSHOT']].flatten, {})
end.show([vm_hash['VM']['TEMPLATE']['SNAPSHOT']].flatten, {})
vm.delete_element("/VM/TEMPLATE/SNAPSHOT")
end
@ -957,7 +990,7 @@ in the frontend machine.
column :"MESSAGE", "", :left, :donottruncate, :size=>35 do |d|
d["MESSAGE"] if !d.nil?
end
end.show([vm.to_hash['VM']['USER_TEMPLATE']['SCHED_ACTION']].flatten, {})
end.show([vm_hash['VM']['USER_TEMPLATE']['SCHED_ACTION']].flatten, {})
end
if vm.has_elements?("/VM/USER_TEMPLATE")

View File

@ -267,6 +267,65 @@ int HostSharePCI::get_pci_value(const char * name,
return 1;
}
/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/
int HostSharePCI::set_pci_address(VectorAttribute * pci_device,
const string& dbus)
{
string bus;
ostringstream oss;
unsigned int ibus, slot;
// ------------------- DOMAIN & FUNCTION -------------------------
pci_device->replace("VM_DOMAIN", "0x0000");
pci_device->replace("VM_FUNCTION", "0");
// --------------------------- BUS -------------------------------
bus = pci_device->vector_value("VM_BUS");
if ( bus.empty() )
{
bus = dbus;
}
istringstream iss(bus);
iss >> hex >> ibus;
if (iss.fail() || !iss.eof())
{
return -1;
}
oss << showbase << internal << setfill('0') << hex << setw(4) << ibus;
pci_device->replace("VM_BUS", oss.str());
// --------------------- SLOT (PCI_ID +1) -----------------------
oss.str("");
pci_device->vector_value("PCI_ID", slot);
slot = slot + 1;
oss << showbase << internal << setfill('0') << hex << setw(4) << slot;
pci_device->replace("VM_SLOT", oss.str());
// ------------------- ADDRESS (BUS:SLOT.0) ---------------------
oss.str("");
oss << noshowbase<<internal<<hex<<setfill('0')<<setw(2) << ibus << ":"
<< noshowbase<<internal<<hex<<setfill('0')<<setw(2) << slot << ".0";
pci_device->replace("VM_ADDRESS", oss.str());
return 0;
}
/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/

View File

@ -22,16 +22,34 @@
# A nil filter will retrieve all PCI cards.
#
# From lspci help:
# -d [<vendor>]:[<device>][:<class>]
# -d [<vendor>]:[<device>]
#
# For example
#
# FILTER = '::0300' # all VGA cards
# FILTER = '10de::0300' # all NVIDIA VGA cards
# FILTER = '10de:11bf:0300' # only GK104GL [GRID K2]
# FILTER = '8086::0300,::0106' # all Intel VGA cards and any SATA controller
# FILTER = '10de:*' # all NVIDIA VGA cards
# FILTER = '10de:11bf' # only GK104GL [GRID K2]
# FILTER = '*:10d3' #Only 82574L Gigabit Network cards
# FILTER = '*:*' # all devices
# FILTER = '0:0' # no devices
#
# You can also filter by the SHORT_ADDRESS, to add only devices in a given address
#
# For example
#
# SHORT_ADDRESS = [ "07:00.0", "06:00.0" ]
#
# Finally you can match devices by device name patterns, only those devices that
# the pattern will be added to the list.
#
# For example
#
# DEVICE_NAME = [ /Virtual Function/, /Gigabit Network/]
#
# Note that these filters, if defined, are all applied
FILTER = "0000:0000"
FILTER = "0:0"
SHORT_ADDRESS = []
DEVICE_NAME = []
require 'shellwords'
@ -89,6 +107,16 @@ def pval(name, value)
end
devices.each do |dev|
next if !SHORT_ADDRESS.empty? && !SHORT_ADDRESS.include?(dev[:short_address])
if !DEVICE_NAME.empty?
matched = DEVICE_NAME.each { |pattern|
break true if !(dev[:device_name] =~ pattern).nil?
}
next if matched != true
end
puts "PCI = ["
values = [
pval('TYPE', dev[:type]),
@ -110,5 +138,3 @@ devices.each do |dev|
puts "]"
end

View File

@ -451,6 +451,7 @@ void OpenNebulaTemplate::set_conf_default()
# MAC_PREFIX
# VLAN_ID
# VXLAN_ID
# PCI_PASSTHROUGH_BUS
#*******************************************************************************
*/
set_conf_single("MAC_PREFIX", "02:00");
@ -468,6 +469,8 @@ void OpenNebulaTemplate::set_conf_default()
vattribute = new VectorAttribute("VXLAN_IDS",vvalue);
conf_default.insert(make_pair(vattribute->name(),vattribute));
set_conf_single("PCI_PASSTHROUGH_BUS", "0x01");
/*
#*******************************************************************************
# Datastore Configuration

View File

@ -675,6 +675,7 @@ define(function(require) {
function ipsStr(element, divider) {
var divider = divider || "<br>"
var nic = element.TEMPLATE.NIC;
var pci = element.TEMPLATE.PCI;
var ips = [];
var monitoring = element.MONITORING;
@ -695,21 +696,35 @@ define(function(require) {
})
}
if (nic == undefined){
nic = [];
}
if (!$.isArray(nic)) {
nic = [nic];
}
if (pci != undefined) {
if (!$.isArray(pci)) {
pci = [pci];
}
$.each(pci, function(){
if (this["TYPE"] == "NIC"){
nic.push(this);
}
});
}
if(ips.length==0)
{
if (nic != undefined) {
if (!$.isArray(nic)) {
nic = [nic];
}
$.each(nic, function(index, value) {
$.each(NIC_IP_ATTRS, function(j, attr){
if (value[attr]) {
ips.push(value[attr]);
}
});
$.each(nic, function(index, value) {
$.each(NIC_IP_ATTRS, function(j, attr){
if (value[attr]) {
ips.push(value[attr]);
}
});
}
});
}
if (ips.length > 0) {

View File

@ -174,6 +174,20 @@ define(function(require) {
delete templateJSON["VCENTER_PUBLIC_CLOUD"];
}
// PCI with TYPE=NIC is not defined in the 'other' tab. Because it is
// part of an array, and it is filled in different tabs, the $.extend deep
// merge can't work. We define an auxiliary attribute for it.
if (templateJSON["NIC_PCI"] != undefined) {
if (templateJSON['PCI'] == undefined) {
templateJSON['PCI'] = [];
}
templateJSON['PCI'] = templateJSON['PCI'].concat(templateJSON["NIC_PCI"]);
delete templateJSON["NIC_PCI"];
}
return templateJSON;
}

View File

@ -75,11 +75,15 @@ define(function(require) {
function _onShow(context, panelForm) {
if (panelForm.action == 'create') {
$('#NAME', context).removeAttr('disabled');
$('#NAME', context).attr("required", "");
$('#NAME', context)
.removeAttr('disabled')
.attr("required", "")
.prop('wizard_field_disabled', false);
} else if (panelForm.action == 'update') {
$('#NAME', context).attr("disabled", "disabled");
$('#NAME', context).removeAttr("required");
$('#NAME', context)
.attr("disabled", "disabled")
.removeAttr("required")
.prop('wizard_field_disabled', true);
}
if (panelForm.resource == "VirtualRouterTemplate"){

View File

@ -113,13 +113,24 @@ define(function(require) {
function _retrieve(context) {
var templateJSON = {}
var nicsJSON = [];
var nicJSON;
var pcisJSON = [];
var tmpJSON;
$.each(this.nicTabObjects, function(id, nicTab) {
nicJSON = nicTab.retrieve($('#' + nicTab.nicTabId, context))
if (!$.isEmptyObject(nicJSON)) {nicsJSON.push(nicJSON)};
tmpJSON = nicTab.retrieve($('#' + nicTab.nicTabId, context))
if (!$.isEmptyObject(tmpJSON)) {
if (tmpJSON["NIC_PCI"] == true){
delete tmpJSON["NIC_PCI"];
tmpJSON["TYPE"] = "NIC";
pcisJSON.push(tmpJSON);
} else {
nicsJSON.push(tmpJSON);
}
};
})
if (nicsJSON.length > 0) { templateJSON['NIC'] = nicsJSON; };
if (pcisJSON.length > 0) { templateJSON['NIC_PCI'] = pcisJSON; };
var nicDefault = WizardFields.retrieveInput($('#DEFAULT_MODEL', context));
if (nicDefault) {
@ -133,27 +144,64 @@ define(function(require) {
function _fill(context, templateJSON) {
var that = this;
var nics = templateJSON.NIC;
if (nics instanceof Array) {
$.each(nics, function(nicId, nicJSON) {
if (nicId > 0) {
that.addNicTab(context);
}
var nics = [];
var nicTab = that.nicTabObjects[that.numberOfNics];
var nicContext = $('#' + nicTab.nicTabId, context);
nicTab.fill(nicContext, nicJSON);
if (templateJSON.NIC != undefined){
nics = templateJSON.NIC;
}
if (!(nics instanceof Array)) {
nics = [nics];
}
if (templateJSON.PCI != undefined){
var pcis = templateJSON.PCI;
if (!(pcis instanceof Array)) {
pcis = [pcis];
}
$.each(pcis, function(){
if (this["TYPE"] == "NIC"){
nics.push(this);
}
});
} else if (nics instanceof Object) {
}
$.each(nics, function(nicId, nicJSON) {
if (nicId > 0) {
that.addNicTab(context);
}
var nicTab = that.nicTabObjects[that.numberOfNics];
var nicContext = $('#' + nicTab.nicTabId, context);
nicTab.fill(nicContext, nics);
}
nicTab.fill(nicContext, nicJSON);
});
if (templateJSON.NIC) {
delete templateJSON.NIC;
}
if (templateJSON.PCI != undefined) {
var pcis = templateJSON.PCI;
if (!(pcis instanceof Array)) {
pcis = [pcis];
}
pcis = pcis.filter(function(pci){
return pci["TYPE"] != "NIC"
});
delete templateJSON.PCI;
if (pcis.length == 1){
templateJSON.PCI = pcis[0];
} else if (pcis.length > 1) {
templateJSON.PCI = pcis;
}
}
var nicDefault = templateJSON.NIC_DEFAULT
if (nicDefault != undefined) {
if (nicDefault.MODEL) {

View File

@ -26,6 +26,7 @@ define(function(require) {
var SecgroupsTable = require('tabs/secgroups-tab/datatable');
var WizardFields = require('utils/wizard-fields');
var UniqueId = require('utils/unique-id');
var CreateUtils = require('../utils');
/*
TEMPLATES
@ -41,7 +42,7 @@ define(function(require) {
CONSTRUCTOR
*/
function DiskTab(nicTabId) {
function NicTab(nicTabId) {
this.nicTabId = 'nicTab' + nicTabId + UniqueId.id();
this.vnetsTable = new VNetsTable(this.nicTabId + 'Table', {'select': true});
@ -55,14 +56,14 @@ define(function(require) {
this.secgroupsTable = new SecgroupsTable(this.nicTabId + 'SGTable', secgroupSelectOptions);
}
DiskTab.prototype.constructor = DiskTab;
DiskTab.prototype.html = _html;
DiskTab.prototype.setup = _setup;
DiskTab.prototype.onShow = _onShow;
DiskTab.prototype.retrieve = _retrieve;
DiskTab.prototype.fill = _fill;
NicTab.prototype.constructor = NicTab;
NicTab.prototype.html = _html;
NicTab.prototype.setup = _setup;
NicTab.prototype.onShow = _onShow;
NicTab.prototype.retrieve = _retrieve;
NicTab.prototype.fill = _fill;
return DiskTab;
return NicTab;
/*
FUNCTION DEFINITIONS
@ -80,8 +81,18 @@ define(function(require) {
this.vnetsTable.refreshResourceTableSelect();
}
function _setup(context) {
/**
* @param {Object} context jquery selector
* @param {Object} options
* options.hide_pci {bool} true to disable the pci checkbox
*/
function _setup(context, options) {
var that = this;
if (options != undefined && options.hide_pci == true){
$("input.pci-type-nic", context).attr('disabled', 'disabled');
}
that.vnetsTable.initialize({
'selectOptions': {
'select_callback': function(aData, options) {
@ -99,6 +110,30 @@ define(function(require) {
that.secgroupsTable.initialize();
that.secgroupsTable.refreshResourceTableSelect();
$("input.pci-type-nic", context).on("change", function(){
var tbody = $(".pci-row tbody", context);
if ($(this).prop('checked')){
$("input[wizard_field=MODEL]", context).prop("disabled", true).prop('wizard_field_disabled', true);
$(".nic-model-row", context).hide();
$(".pci-row", context).show();
tbody.html( CreateUtils.pciRowHTML() );
CreateUtils.fillPCIRow({tr: $('tr', tbody), remove: false});
} else {
$("input[wizard_field=MODEL]", context).removeAttr('disabled').prop('wizard_field_disabled', false);
$(".nic-model-row", context).show();
$(".pci-row", context).hide();
tbody.html("");
}
});
CreateUtils.setupPCIRows($(".pci-row", context));
$("input.pci-type-nic", context).change();
}
function _retrieve(context) {
@ -123,6 +158,10 @@ define(function(require) {
nicJSON["SECURITY_GROUPS"] = secgroups.join(",");
}
if ($("input.pci-type-nic", context).prop("checked")){
nicJSON["NIC_PCI"] = true;
}
return nicJSON;
}
@ -182,6 +221,10 @@ define(function(require) {
this.secgroupsTable.refreshResourceTableSelect();
}
if (templateJSON["TYPE"] == "NIC"){
$("input.pci-type-nic", context).click();
}
WizardFields.fill(context, templateJSON);
}
});

View File

@ -130,6 +130,14 @@
<fieldset>
<legend>{{tr "Hardware"}}</legend>
<div class="row">
<div class="small-12 columns">
<label>
<input type="checkbox" class="pci-type-nic"/>
{{tr "PCI passthrough"}}
</label>
</div>
</div>
<div class="row nic-model-row">
<div class="medium-6 columns">
<label for="MODEL">
{{tr "Hardware model to emulate"}}
@ -137,8 +145,24 @@
<input type="text" wizard_field="MODEL" id="MODEL" name="MODEL" />
</div>
</div>
<div class="row pci-row">
<div class="small-12 columns">
<table>
<thead>
<tr>
<th style="width:50%">{{tr "Device name"}}</th>
<th>{{tr "Vendor"}}</th>
<th>{{tr "Device"}}</th>
<th>{{tr "Class"}}</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</fieldset>
<br>
<fieldset>
<legend>{{tr "Security Groups"}}</legend>
<div name="str_nic_tab_id" str_nic_tab_id="{{nicTabId}}">

View File

@ -27,13 +27,13 @@ define(function(require) {
var CustomTagsTable = require('utils/custom-tags-table');
var OpenNebulaHost = require('opennebula/host');
var UniqueId = require('utils/unique-id');
var CreateUtils = require('./utils');
/*
TEMPLATES
*/
var TemplateHTML = require('hbs!./other/html');
var RowTemplateHTML = require('hbs!./other/pciRow');
/*
CONSTANTS
@ -82,65 +82,12 @@ define(function(require) {
context.off("click", ".add_pci");
context.on("click", ".add_pci", function(){
var tr = $(RowTemplateHTML()).appendTo( $(".pci_devices tbody", context) );
var tr = $(CreateUtils.pciRowHTML()).appendTo( $(".pci_devices tbody", context) );
OpenNebulaHost.pciDevices({
data : {},
timeout: true,
success: function (request, pciDevices){
var html = "<select>";
html += '<option device="" class="" vendor="">'+Locale.tr("Please select")+'</option>';
$.each(pciDevices, function(i,pci){
html += '<option device="'+pci['device']+'" '+
'class="'+pci['class']+'" '+
'vendor="'+pci['vendor']+'">'+
pci.device_name+
'</option>';
});
html += '</select>';
$(".device_name", tr).html(html);
$("input", tr).trigger("change");
},
error: function(request, error_json){
console.error("There was an error requesting the PCI devices: "+
error_json.error.message);
$(".device_name", tr).html("");
}
});
CreateUtils.fillPCIRow({tr: tr, remove: true});
});
context.on("change", ".pci_devices td.device_name select", function(){
var tr = $(this).closest('tr');
var option = $("option:selected", this);
$('input[wizard_field="DEVICE"]', tr).val( option.attr("device") );
$('input[wizard_field="CLASS"]', tr).val( option.attr("class") );
$('input[wizard_field="VENDOR"]', tr).val( option.attr("vendor") );
});
context.on("change", ".pci_devices tbody input", function(){
var tr = $(this).closest('tr');
var opt =
$('option'+
'[device="'+$('input[wizard_field="DEVICE"]', tr).val()+'"]'+
'[class="'+$('input[wizard_field="CLASS"]', tr).val()+'"]'+
'[vendor="'+$('input[wizard_field="VENDOR"]', tr).val()+'"]', tr);
opt.attr('selected', 'selected');
});
context.on("click", ".pci_devices i.remove-tab", function(){
var tr = $(this).closest('tr');
tr.remove();
});
CreateUtils.setupPCIRows($(".pci_devices", context));
}
function _retrieve(context) {

View File

@ -38,7 +38,14 @@
</fieldset>
<fieldset class="hypervisor only_kvm vm_updateconf_hide">
<legend>{{tr "PCI Devices"}}</legend>
<div>
<div class="row">
<div class="large-12 columns text-center">
<span class="radius secondary label">
<i class="fa fa-warning"/> {{tr "PCI passthrough of network devices is configured per NIC, in the \"Network\" tab. Do not add network devices here"}}
</span>
</div>
</div>
<div class="row">
<div class="large-12 columns">
<table class="dataTable pci_devices">
<thead>

View File

@ -0,0 +1,118 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2016, OpenNebula Project, OpenNebula Systems */
/* */
/* 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. */
/* -------------------------------------------------------------------------- */
define(function(require) {
/* DEPENDENCIES */
var OpenNebulaHost = require('opennebula/host');
var Locale = require('utils/locale');
var RowTemplateHTML = require('hbs!./utils/pciRow');
return {
'pciRowHTML': _pciRowHTML,
'fillPCIRow': _fillPCIRow,
'setupPCIRows': _setupPCIRows
};
function _pciRowHTML(){
return RowTemplateHTML();
}
/**
* Fills the PCI row with values taken from an ajax call to oned
*
* @param {Object} opts Options:
* @param {JQuery} opts.tr tr created with pciRowHTML
* @param {bool} opts.remove true (default) to show the remove tr button
*
*/
function _fillPCIRow(opts){
OpenNebulaHost.pciDevices({
data : {},
timeout: true,
success: function (request, pciDevices){
var tr = opts.tr;
var html = "<select>";
html += '<option device="" class="" vendor="">'+Locale.tr("Please select")+'</option>';
$.each(pciDevices, function(i,pci){
html += '<option device="'+pci['device']+'" '+
'class="'+pci['class']+'" '+
'vendor="'+pci['vendor']+'">'+
pci.device_name+
'</option>';
});
html += '</select>';
$(".device_name", opts.tr).html(html);
$("input", opts.tr).trigger("change");
if (opts.remove === false){
$("i.remove-tab", opts.tr).hide();
}
},
error: function(request, error_json){
console.error("There was an error requesting the PCI devices: "+
error_json.error.message);
$(".device_name", opts.tr).html("");
if (opts.remove === false){
$("i.remove-tab", opts.tr).hide();
}
}
});
}
/**
* Setups the pci rows. Can be called once, will work for future rows created
* later
*/
function _setupPCIRows(context){
context.on("change", "td.device_name select", function(){
var tr = $(this).closest('tr');
var option = $("option:selected", this);
$('input[wizard_field="DEVICE"]', tr).val( option.attr("device") );
$('input[wizard_field="CLASS"]', tr).val( option.attr("class") );
$('input[wizard_field="VENDOR"]', tr).val( option.attr("vendor") );
});
context.on("change", "tbody input", function(){
var tr = $(this).closest('tr');
var opt =
$('option'+
'[device="'+$('input[wizard_field="DEVICE"]', tr).val()+'"]'+
'[class="'+$('input[wizard_field="CLASS"]', tr).val()+'"]'+
'[vendor="'+$('input[wizard_field="VENDOR"]', tr).val()+'"]', tr);
opt.attr('selected', 'selected');
});
context.on("click", "i.remove-tab", function(){
var tr = $(this).closest('tr');
tr.remove();
});
}
});

View File

@ -124,6 +124,8 @@ define(function(require) {
}
function _submitWizard(context) {
var that = this;
if (!this.selected_nodes || this.selected_nodes.length == 0) {
Notifier.notifyError(Locale.tr("No template selected"));
Sunstone.hideFormPanelLoading(this.tabId);
@ -160,11 +162,50 @@ define(function(require) {
tmp_json.DISK = disks;
}
var nics = NicsSection.retrieve($(".nicsContext" + template_id, context));
var networks = NicsSection.retrieve($(".nicsContext" + template_id, context));
var nics = [];
var pcis = [];
$.each(networks, function(){
if (this.TYPE == "NIC"){
pcis.push(this);
}else{
nics.push(this);
}
});
if (nics.length > 0) {
tmp_json.NIC = nics;
}
// Replace PCIs of type nic only
var original_tmpl = that.template_objects[index].VMTEMPLATE;
var regular_pcis = [];
if(original_tmpl.TEMPLATE.PCI != undefined){
var original_pcis;
if ($.isArray(original_tmpl.TEMPLATE.PCI)){
original_pcis = original_tmpl.TEMPLATE.PCI;
} else if (!$.isEmptyObject(original_tmpl.TEMPLATE.PCI)){
original_pcis = [original_tmpl.TEMPLATE.PCI];
}
$.each(original_pcis, function(){
if(this.TYPE != "NIC"){
regular_pcis.push(this);
}
});
}
pcis = pcis.concat(regular_pcis);
if (pcis.length > 0) {
tmp_json.PCI = pcis;
}
capacityContext = $(".capacityContext" + template_id, context);
$.extend(tmp_json, CapacityInputs.retrieveChanges(capacityContext));

View File

@ -69,7 +69,7 @@ define(function(require) {
function _setup(context) {
var that = this;
that.nicTab.setup(context);
that.nicTab.setup(context, {hide_pci: true});
Tips.setup(context);

View File

@ -80,6 +80,7 @@ define(function(require) {
<th>' + Locale.tr("Network") + '</th>\
<th>' + Locale.tr("IP") + '</th>\
<th>' + Locale.tr("MAC") + '</th>\
<th>' + Locale.tr("PCI address") + '</th>\
<th>' + Locale.tr("IPv6 ULA") + '</th>\
<th>' + Locale.tr("IPv6 Global") + '</th>\
<th colspan="">' + Locale.tr("Actions") + '</th>\
@ -207,15 +208,44 @@ define(function(require) {
return html;
}
function _ipTr(nic, attr){
var v = "--";
if (nic[attr] != undefined){
v = nic[attr];
if (nic["VROUTER_"+attr] != undefined){
v += ("<br/>" + nic["VROUTER_"+attr] + Locale.tr(" (VRouter)"));
}
}
return v;
}
function _setup(context) {
var that = this;
var nics = []
if ($.isArray(that.element.TEMPLATE.NIC))
nics = that.element.TEMPLATE.NIC
else if (!$.isEmptyObject(that.element.TEMPLATE.NIC))
nics = [that.element.TEMPLATE.NIC]
if ($.isArray(that.element.TEMPLATE.NIC)){
nics = that.element.TEMPLATE.NIC;
} else if (!$.isEmptyObject(that.element.TEMPLATE.NIC)){
nics = [that.element.TEMPLATE.NIC];
}
var pcis = [];
if ($.isArray(that.element.TEMPLATE.PCI)){
pcis = that.element.TEMPLATE.PCI;
} else if (!$.isEmptyObject(that.element.TEMPLATE.PCI)){
pcis = [that.element.TEMPLATE.PCI];
}
$.each(pcis, function(){
if(this.NIC_ID != undefined){
nics.push(this);
}
});
var nic_dt_data = [];
if (nics.length) {
@ -224,22 +254,18 @@ define(function(require) {
for (var i = 0; i < nics.length; i++) {
var nic = nics[i];
var actions;
// Attach / Detach
if (
(
that.element.STATE == OpenNebulaVM.STATES.ACTIVE) &&
(
that.element.LCM_STATE == OpenNebulaVM.LCM_STATES.HOTPLUG_NIC) &&
(
nic.ATTACH == "YES")
) {
actions = Locale.tr("attach/detach in progress")
} else {
actions = '';
var is_pci = (nic.PCI_ID != undefined);
if (Config.isTabActionEnabled("vms-tab", "VM.detachnic")) {
if (StateActions.enabledStateAction("VM.detachnic", that.element.STATE, that.element.LCM_STATE)) {
var actions = '';
// Attach / Detach
if (!is_pci){
if ( (that.element.STATE == OpenNebulaVM.STATES.ACTIVE) &&
(that.element.LCM_STATE == OpenNebulaVM.LCM_STATES.HOTPLUG_NIC) &&
(nic.ATTACH == "YES") ) {
actions = Locale.tr("attach/detach in progress")
} else {
if ( (Config.isTabActionEnabled("vms-tab", "VM.detachnic")) &&
(StateActions.enabledStateAction("VM.detachnic", that.element.STATE, that.element.LCM_STATE))) {
actions += '<a href="VM.detachnic" class="detachnic" ><i class="fa fa-times"/>' + Locale.tr("Detach") + '</a>'
}
}
@ -268,27 +294,16 @@ define(function(require) {
});
}
function ipTr(attr){
var v = "--";
if (nic[attr] != undefined){
v = nic[attr];
if (nic["VROUTER_"+attr] != undefined){
v += ("<br/>" + nic["VROUTER_"+attr] + Locale.tr(" (VRouter)"));
}
}
return v;
}
var pci_address = is_pci ? nic.ADDRESS : '';
nic_dt_data.push({
NIC_ID : nic.NIC_ID,
NETWORK : nic.NETWORK,
IP : ipTr("IP"),
IP : _ipTr(nic, "IP"),
MAC : nic.MAC,
IP6_ULA : ipTr("IP6_ULA"),
IP6_GLOBAL : ipTr("IP6_GLOBAL"),
PCI_ADDRESS: pci_address,
IP6_ULA : _ipTr(nic, "IP6_ULA"),
IP6_GLOBAL : _ipTr(nic, "IP6_GLOBAL"),
ACTIONS : actions,
SECURITY_GROUP_RULES : secgroups
});
@ -309,6 +324,7 @@ define(function(require) {
{"data": "NETWORK", "defaultContent": ""},
{"data": "IP", "defaultContent": "", "class": "nowrap"},
{"data": "MAC", "defaultContent": ""},
{"data": "PCI_ADDRESS","defaultContent": ""},
{"data": "IP6_ULA", "defaultContent": "", "class": "nowrap"},
{"data": "IP6_GLOBAL", "defaultContent": "", "class": "nowrap"},
{"data": "ACTIONS", "defaultContent": "", "orderable": false},

View File

@ -55,11 +55,28 @@ define(function(require) {
try {
if (OpenNebulaTemplate.isNetworkChangeEnabled(template_json)) {
var template_nic = template_json.VMTEMPLATE.TEMPLATE.NIC
var nics = []
if ($.isArray(template_nic))
nics = template_nic
else if (!$.isEmptyObject(template_nic))
nics = [template_nic]
var nics = [];
if ($.isArray(template_nic)){
nics = template_nic;
} else if (!$.isEmptyObject(template_nic)){
nics = [template_nic];
}
var pcis = [];
if ($.isArray(template_json.VMTEMPLATE.TEMPLATE.PCI)){
pcis = template_json.VMTEMPLATE.TEMPLATE.PCI;
} else if (!$.isEmptyObject(template_json.VMTEMPLATE.TEMPLATE.PCI)){
pcis = [template_json.VMTEMPLATE.TEMPLATE.PCI];
}
$.each(pcis, function(){
if(this.TYPE == "NIC"){
nics.push(this);
}
});
_generate_provision_network_accordion(
$(".provision_network_selector", context), options);
@ -68,6 +85,8 @@ define(function(require) {
var opt = $.extend({}, options);
opt.nic = nic;
opt.pci = (nic.TYPE == "NIC");
_generate_provision_network_table(
$(".provision_nic_accordion", context),
opt);
@ -160,6 +179,7 @@ define(function(require) {
* - management {bool}: true to show the
* management checkbox
* - securityGroups {bool}: true to select SGs
* - pci {bool}: true if this is a PCI interface
*/
function _generate_provision_network_table(context, options) {
context.off();

View File

@ -2,7 +2,11 @@
<a href="#provision_accordion_dd_{{provision_nic_accordion_dd_id}}" class="accordion-title">
<i class="only-not-active fa fa-chevron-down"/>
<i class="only-active fa fa-chevron-up"/>
{{#if options.pci}}
&nbsp;{{tr "PCI interface"}}&nbsp;
{{else}}
&nbsp;{{tr "Interface"}}&nbsp;
{{/if}}
<span class="selected_network">
{{#if options.nic}}
{{#if options.nic.NETWORK}}

View File

@ -145,9 +145,10 @@ const char * VirtualMachine::NETWORK_CONTEXT[][2] = {
{"DNS", "DNS"},
{"SEARCH_DOMAIN", "SEARCH_DOMAIN"},
{"MTU", "GUEST_MTU"},
{"VLAN_ID", "VLAN_ID"},
{"VROUTER_IP", "VROUTER_IP"},
{"VROUTER_MANAGEMENT", "VROUTER_MANAGEMENT"}};
const int VirtualMachine::NUM_NETWORK_CONTEXT = 10;
const int VirtualMachine::NUM_NETWORK_CONTEXT = 11;
const char* VirtualMachine::NETWORK6_CONTEXT[][2] = {
{"IP6", "IP6_GLOBAL"},
@ -552,6 +553,17 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
goto error_os;
}
// ------------------------------------------------------------------------
// PCI Devices (Needs to be parsed before network)
// ------------------------------------------------------------------------
rc = parse_pci(error_str);
if ( rc != 0 )
{
goto error_pci;
}
// ------------------------------------------------------------------------
// Parse the defaults to merge
// ------------------------------------------------------------------------
@ -612,17 +624,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
state = VirtualMachine::CLONING;
}
// ------------------------------------------------------------------------
// PCI Devices
// ------------------------------------------------------------------------
rc = parse_pci(error_str);
if ( rc != 0 )
{
goto error_pci;
}
// -------------------------------------------------------------------------
// Set boot order
// -------------------------------------------------------------------------
@ -706,9 +707,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
error_update:
goto error_rollback;
error_pci:
goto error_rollback;
error_boot_order:
goto error_rollback;
@ -757,6 +755,7 @@ error_one_vms:
goto error_common;
error_os:
error_pci:
error_defaults:
error_vrouter:
error_public:
@ -1067,6 +1066,8 @@ int VirtualMachine::parse_context(string& error_str)
return -1;
}
generate_pci_context(context);
// -------------------------------------------------------------------------
// Parse FILE_DS variables
// -------------------------------------------------------------------------
@ -1204,60 +1205,71 @@ int VirtualMachine::parse_context_variables(VectorAttribute ** context,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static int check_pci_attributes(VectorAttribute * pci, const string& default_bus,
string& error_str)
{
static string attrs[] = {"VENDOR", "DEVICE", "CLASS"};
static int num_attrs = 3;
string bus;
bool found = false;
for (int i = 0; i < num_attrs; i++)
{
unsigned int val;
int rc = HostSharePCI::get_pci_value(attrs[i].c_str(), pci, val);
if (rc == -1)
{
error_str = "Wrong Hex value for PCI attribute " + attrs[i];
return -1;
}
else if ( rc != 0 )
{
found = true;
}
}
if (!found)
{
error_str = "DEVICE, VENDOR or CLASS must be defined for PCI.";
return -1;
}
if ( HostSharePCI::set_pci_address(pci, default_bus) != 0 )
{
error_str = "Wrong BUS in PCI attribute";
return -1;
}
return 0;
}
int VirtualMachine::parse_pci(string& error_str)
{
VectorAttribute * pci;
vector<Attribute *> array_pci;
vector<Attribute *>::iterator it;
vector<VectorAttribute *> array_pci;
vector<VectorAttribute *>::iterator it;
unsigned int val;
int pci_id = 0;
user_obj_template->remove("PCI", array_pci);
static string attrs[] = {"VENDOR", "DEVICE", "CLASS"};
for (it = array_pci.begin(); it !=array_pci.end(); it++)
for (it = array_pci.begin(); it !=array_pci.end(); ++it, ++pci_id)
{
(*it)->replace("PCI_ID", pci_id);
obj_template->set(*it);
}
for (it = array_pci.begin(); it !=array_pci.end(); it++)
Nebula& nd = Nebula::instance();
string default_bus;
nd.get_configuration_attribute("PCI_PASSTHROUGH_BUS", default_bus);
for (it = array_pci.begin(); it !=array_pci.end(); ++it)
{
bool found = false;
pci = dynamic_cast<VectorAttribute * >(*it);
if ( pci == 0 )
if ( check_pci_attributes(*it, default_bus, error_str) != 0 )
{
error_str = "PCI attribute must be a vector attribute";
return -1;
}
for (int i=0; i<3; i++)
{
int rc = HostSharePCI::get_pci_value(attrs[i].c_str(), pci, val);
if (rc == -1)
{
ostringstream oss;
oss << "Wrong value for PCI/" << attrs[i] << ": "
<< pci->vector_value(attrs[i].c_str())
<<". It must be a hex value";
error_str = oss.str();
return -1;
}
else if ( rc != 0 )
{
found = true;
}
}
if (!found)
{
error_str = "Missing mandatory attributes inside PCI. "
"Either DEVICE, VENDOR or CLASS must be defined";
return -1;
}
}
@ -1529,6 +1541,27 @@ int VirtualMachine::automatic_requirements(string& error_str)
}
}
vatts.clear();
// Get cluster id from all PCI attibutes, TYPE = NIC
num_vatts = obj_template->get("PCI", vatts);
for(int i=0; i<num_vatts; i++)
{
if ( vatts[i]->vector_value("TYPE") != "NIC" )
{
continue;
}
rc = check_and_set_cluster_id("CLUSTER_ID", vatts[i], cluster_ids);
if ( rc != 0 )
{
incomp_id = i;
goto error_pci;
}
}
if ( !cluster_ids.empty() )
{
set<int>::iterator i = cluster_ids.begin();
@ -1642,6 +1675,21 @@ error_nic:
goto error_common;
error_pci:
if (rc == -1)
{
oss << "Incompatible clusters in PCI (TYPE=NIC). Network for PCI "<< incomp_id
<< " is not the same as the one used by other VM elements (cluster "
<< one_util::join(cluster_ids, ',') << ")";
}
else
{
oss << "Missing clusters. Network for PCI "<< incomp_id
<< " is not in any cluster";
}
goto error_common;
error_common:
error_str = oss.str();
@ -3159,6 +3207,23 @@ int VirtualMachine::get_network_leases(string& estr)
}
}
vector<VectorAttribute *> pcis;
int num_pcis = get_template_attribute("PCI", pcis);
for (int i = 0; i < num_pcis; ++i)
{
if ( pcis[i]->vector_value("TYPE") == "NIC" )
{
rc = vnpool->nic_attribute(PoolObjectSQL::VM, pcis[i], i, uid, oid, estr);
if ( rc == -1 )
{
return -1;
}
}
}
get_security_groups(vm_sgs);
sgpool->get_security_group_rules(get_oid(), vm_sgs, sg_rules);
@ -3191,12 +3256,23 @@ void VirtualMachine::release_network_leases()
string vnid;
string ip;
vector<VectorAttribute const * > nics;
int num_nics = get_template_attribute("NIC",nics);
vector<VectorAttribute const *> vatts;
for(int i=0; i<num_nics; i++)
int num = get_template_attribute("NIC", vatts);
for(int i = 0; i < num; i++)
{
release_network_leases(nics[i], oid);
release_network_leases(vatts[i], oid);
}
num = get_template_attribute("PCI", vatts);
for(int i = 0; i < num; i++)
{
if ( vatts[i]->vector_value("TYPE") == "NIC" )
{
release_network_leases(vatts[i], oid);
}
}
}
@ -3264,15 +3340,26 @@ int VirtualMachine::release_network_leases(const VectorAttribute * nic, int vmid
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualMachine::get_security_groups(set<int>& sgs) const
void VirtualMachine::get_security_groups(VirtualMachineTemplate *tmpl, set<int>& sgs)
{
vector<VectorAttribute *> ns;
int num_nics = obj_template->get("NIC", ns);
vector<VectorAttribute const *> vatts;
for(int i=0; i<num_nics; i++)
int num = tmpl->get("NIC", vatts);
for(int i = 0; i < num; i++)
{
get_security_groups(ns[i], sgs);
get_security_groups(vatts[i], sgs);
}
num = tmpl->get("PCI", vatts);
for(int i = 0; i < num; i++)
{
if ( vatts[i]->vector_value("TYPE") == "NIC" )
{
get_security_groups(vatts[i], sgs);
}
}
}
@ -3733,7 +3820,6 @@ void VirtualMachine::set_auth_request(int uid,
AuthRequest& ar,
VirtualMachineTemplate *tmpl)
{
int num;
vector<VectorAttribute *> vectors;
Nebula& nd = Nebula::instance();
@ -3742,10 +3828,7 @@ void VirtualMachine::set_auth_request(int uid,
VirtualNetworkPool * vnpool = nd.get_vnpool();
SecurityGroupPool * sgpool = nd.get_secgrouppool();
set<int> sgroups;
SecurityGroup * sgroup;
num = tmpl->get("DISK", vectors);
int num = tmpl->get("DISK", vectors);
for(int i=0; i<num; i++)
{
@ -3756,25 +3839,28 @@ void VirtualMachine::set_auth_request(int uid,
num = tmpl->get("NIC", vectors);
for(int i=0; i<num; i++, sgroups.clear())
for(int i=0; i<num; i++)
{
vnpool->authorize_nic(PoolObjectSQL::VM, vectors[i], uid, &ar);
}
get_security_groups(vectors[i], sgroups);
set<int> sgroups;
for(set<int>::iterator it = sgroups.begin(); it != sgroups.end(); it++)
get_security_groups(tmpl, sgroups);
for(set<int>::iterator it = sgroups.begin(); it != sgroups.end(); it++)
{
SecurityGroup * sgroup = sgpool->get(*it, true);
if(sgroup != 0)
{
sgroup = sgpool->get(*it, true);
PoolObjectAuth perm;
if(sgroup != 0)
{
PoolObjectAuth perm;
sgroup->get_permissions(perm);
sgroup->get_permissions(perm);
sgroup->unlock();
sgroup->unlock();
ar.add_auth(AuthRequest::USE, perm);
}
ar.add_auth(AuthRequest::USE, perm);
}
}
}
@ -3796,7 +3882,6 @@ void VirtualMachine::disk_extended_info(int uid,
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -4761,7 +4846,6 @@ static void parse_context_network(const char* vars[][2], int num_vars,
cvar << "ETH" << nic_id << "_" << vars[i][0];
cval = context->vector_value(cvar.str().c_str());
cval = nic->vector_value(vars[i][1]); //Check the NIC
if (cval.empty()) //Will check the AR and VNET
@ -4778,6 +4862,29 @@ static void parse_context_network(const char* vars[][2], int num_vars,
/* -------------------------------------------------------------------------- */
static void parse_pci_context_network(const char* vars[][2], int num_vars,
VectorAttribute * context, VectorAttribute * nic)
{
string pci_id = nic->vector_value("PCI_ID");
for (int i=0; i < num_vars; i++)
{
ostringstream cvar;
cvar << "PCI" << pci_id << "_" << vars[i][0];
string cval = nic->vector_value(vars[i][1]);
if (!cval.empty())
{
context->replace(cvar.str(), cval);
}
}
}
/* -------------------------------------------------------------------------- */
void VirtualMachine::parse_nic_context(VectorAttribute * c, VectorAttribute * n)
{
parse_context_network(NETWORK_CONTEXT, NUM_NETWORK_CONTEXT, c, n);
@ -4786,6 +4893,42 @@ void VirtualMachine::parse_nic_context(VectorAttribute * c, VectorAttribute * n)
/* -------------------------------------------------------------------------- */
bool VirtualMachine::generate_pci_context(VectorAttribute * context)
{
bool net_context;
vector<VectorAttribute *> vatts;
context->vector_value("NETWORK", net_context);
int num_vatts = obj_template->get("PCI", vatts);
for(int i=0; i<num_vatts; i++)
{
if ( net_context && vatts[i]->vector_value("TYPE") == "NIC" )
{
parse_pci_context_network(NETWORK_CONTEXT, NUM_NETWORK_CONTEXT,
context, vatts[i]);
parse_pci_context_network(NETWORK6_CONTEXT, NUM_NETWORK6_CONTEXT,
context, vatts[i]);
}
ostringstream cvar;
cvar << "PCI" << vatts[i]->vector_value("PCI_ID") << "_ADDRESS";
string cval = vatts[i]->vector_value("VM_ADDRESS");
if (!cval.empty())
{
context->replace(cvar.str(), cval);
}
}
return net_context;
}
/* -------------------------------------------------------------------------- */
bool VirtualMachine::generate_network_context(VectorAttribute * context)
{
bool net_context;

View File

@ -184,10 +184,15 @@ int LibVirtDriver::deployment_description_kvm(
vector<const VectorAttribute *> pci;
string domain = "";
string domain = "";
/* bus is already defined for disks */
string slot = "";
string func = "";
string slot = "";
string func = "";
string vm_domain = "";
string vm_bus = "";
string vm_slot = "";
string vm_func = "";
const VectorAttribute * features;
@ -1014,6 +1019,11 @@ int LibVirtDriver::deployment_description_kvm(
slot = pci[i]->vector_value("SLOT");
func = pci[i]->vector_value("FUNCTION");
vm_domain = pci[i]->vector_value("VM_DOMAIN");
vm_bus = pci[i]->vector_value("VM_BUS");
vm_slot = pci[i]->vector_value("VM_SLOT");
vm_func = pci[i]->vector_value("VM_FUNCTION");
if ( domain.empty() || bus.empty() || slot.empty() || func.empty() )
{
vm->log("VMM", Log::WARNING,
@ -1033,6 +1043,17 @@ int LibVirtDriver::deployment_description_kvm(
<< "/>\n";
file << "\t\t\t</source>\n";
if ( !vm_domain.empty() && !vm_bus.empty() && !vm_slot.empty() &&
!vm_func.empty() )
{
file << "\t\t\t\t<address type='pci'"
<< " domain=" << one_util::escape_xml_attr(vm_domain)
<< " bus=" << one_util::escape_xml_attr(vm_bus)
<< " slot=" << one_util::escape_xml_attr(vm_slot)
<< " function=" << one_util::escape_xml_attr(vm_func)
<< "/>\n";
}
file << "\t\t</hostdev>" << endl;
}