1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-15 18:50:09 +03:00

feature #3208: Add PCI device set to the HostShare

This commit is contained in:
Ruben S. Montero 2015-08-20 17:39:56 +02:00
parent 6b8a16fc76
commit e04ee43aa3
2 changed files with 370 additions and 31 deletions

View File

@ -20,22 +20,149 @@
#include "ObjectXML.h"
#include "Template.h"
#include <time.h>
using namespace std;
#include <set>
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
class HostShareTemplate : public Template
class HostShareDatastore : public Template
{
public:
HostShareTemplate(const char * name) : Template(false, '=', name){};
HostShareDatastore() : Template(false, '=', "DATASTORE"){};
~HostShareTemplate(){};
virtual ~HostShareDatastore(){};
};
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
/**
* This class represents a PCI DEVICE list for the host. The list is in the
* form:
* <PCI>
* <TYPE>: Three 4-hex digits groups representing <vendor>:<device>:<class>
* <DESCRIPTION>: The corresponding device description
* <ADDRESS>: PCI address, bus, slot and function
*/
class HostSharePCI : public Template
{
public:
HostSharePCI() : Template(false, '=', "PCI_DEVICES"){};
virtual ~HostSharePCI()
{
map<string, PCIDevice *>::iterator it;
for (it=pci_devices.begin(); it != pci_devices.end(); it++)
{
delete it->second;
};
};
/**
* Builds the devices list from its XML representation. This function
* is used when importing it from the DB.
* @param node xmlNode for the template
* @return 0 on success
*/
int from_xml_node(const xmlNodePtr node);
/**
* Test wether this PCI device set has the requested devices available.
* @param devs list of requested devices by the VM.
* @return true if all the devices are available.
*/
bool test(vector<Attribute *> &devs)
{
return test_set(devs, -1);
}
/**
* Assign the requested devices to the given VM. The assgined devices will
* be labeled with the VM and the PCI attribute of the VM extended with
* the address of the assigned devices.
* @param devs list of requested PCI devices, will include address of
* assgined devices.
* @param vmid of the VM
*/
void add(vector<Attribute *> &devs, int vmid)
{
test_set(devs, vmid);
}
/**
* Remove the VM assigment from the PCI device list
*/
void del(const vector<Attribute *> &devs);
/**
* Updates the PCI list with monitor data, it will create or
* remove PCIDevices as needed.
*/
void set_monitorization(vector<Attribute*> &pci_att);
private:
/**
* Sets the internal class structures from the template
*/
int init();
/**
* Test if a PCIDevice matches the vendor, device and class request spec
* and can be assigned. It will assgin it if requested.
* @param vendor_id id in uint form 0 means *
* @param device_id id in uint form 0 means *
* @param class_id id in uint form 0 means *
* @param pci requested pci device
* @param vmid if not -1 it will also assign the PCI device to the VM,
* and the pci attribute will be extended with device information.
* @param assgined set of addresses already assgined devices, it will
* include the selected device if found; useful to iterate.
*
* @return true if a device was found.
*/
bool test_set(unsigned int vendor_id, unsigned int device_id,
unsigned int class_id, VectorAttribute *pci, int vmid,
std::set<string> &assigned);
/**
* Test if the given list of PCIDevices can be assigned to the VM
* @param devs, list of PCI devices
* @param vmid if not -1 it will assign the devices to the VM
*
* @return true if the PCIDevice list can be assgined.
*/
bool test_set(vector<Attribute *> &devs, int vmid);
/**
* Gets a 4 hex digits value from attribute
* @param name of the attribute
* @pci_device VectorAttribute representing the device
* @return the value as unsigned int or 0 if was not found
*/
static unsigned int get_pci_value(const char * name,
const VectorAttribute * pci_device);
/**
* Internal structure to represent PCI devices for fast look up and
* update
*/
struct PCIDevice
{
PCIDevice(VectorAttribute * _attrs);
~PCIDevice(){};
unsigned int vendor_id;
unsigned int device_id;
unsigned int class_id;
int vmid;
string address;
VectorAttribute * attrs;
};
map <string, PCIDevice *> pci_devices;
};
/**
* The HostShare class. It represents a logical partition of a host...
@ -125,7 +252,10 @@ public:
void set_ds_monitorization(const vector<Attribute*> &ds_att);
void set_pci_monitorization(const vector<Attribute*> &pci_att);
void set_pci_monitorization(vector<Attribute*> &pci_att)
{
pci.set_monitorization(pci_att);
}
private:
@ -147,8 +277,8 @@ private:
long long running_vms;/**< Number of running VMs in this Host */
HostShareTemplate ds_template;
HostShareTemplate pci_template;
HostShareDatastore ds;
HostSharePCI pci;
// ----------------------------------------
// Friends

View File

@ -15,7 +15,6 @@
/* ------------------------------------------------------------------------*/
#include <limits.h>
#include <string.h>
#include <iostream>
#include <sstream>
@ -23,6 +22,228 @@
#include "HostShare.h"
using namespace std;
/* ************************************************************************ */
/* HostSharePCI */
/* ************************************************************************ */
int HostSharePCI::from_xml_node(const xmlNodePtr node)
{
int rc = from_xml_node(node);
if (rc != 0)
{
return -1;
}
return init();
}
int HostSharePCI::init()
{
vector<Attribute *> devices;
int num_devs = get("PCI", devices);
for (int i=0; i < num_devs; i++)
{
VectorAttribute * pci = dynamic_cast<VectorAttribute *>(devices[i]);
if (pci == 0)
{
return -1;
}
PCIDevice * pcidev = new PCIDevice(pci);
pci_devices.insert(make_pair(pcidev->address, pcidev));
}
return 0;
}
/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/
bool HostSharePCI::test_set(unsigned int vendor_id, unsigned int device_id,
unsigned int class_id, VectorAttribute * devreq, int vmid,
std::set<string>& assigned)
{
map<string, PCIDevice *>::iterator it;
for (it=pci_devices.begin(); it!=pci_devices.end(); it++)
{
PCIDevice * dev = it->second;
if (dev->class_id == class_id &&
dev->vendor_id == vendor_id &&
dev->device_id == device_id &&
dev->vmid == -1 &&
assigned.find(dev->address) == assigned.end())
{
assigned.insert(dev->address);
if (vmid != -1)
{
dev->vmid = vmid;
dev->attrs->replace("VMID", vmid);
devreq->replace("DOMAIN",dev->attrs->vector_value("DOMAIN"));
devreq->replace("BUS",dev->attrs->vector_value("BUS"));
devreq->replace("SLOT",dev->attrs->vector_value("SLOT"));
devreq->replace("FUNCTION",dev->attrs->vector_value("FUNCTION"));
devreq->replace("ADDRESS",dev->attrs->vector_value("ADDRESS"));
}
return true;
}
}
return false;
}
/* ------------------------------------------------------------------------*/
bool HostSharePCI::test_set(vector<Attribute *> &devs, int vmid)
{
vector<Attribute *>::iterator it;
std::set<string> assigned;
unsigned int vendor_id, device_id, class_id;
for ( it=devs.begin(); it!= devs.end(); it++)
{
VectorAttribute * pci = dynamic_cast<VectorAttribute *>(*it);
if ( pci == 0 )
{
return false;
}
vendor_id = get_pci_value("VENDOR", pci);
device_id = get_pci_value("DEVICE", pci);
class_id = get_pci_value("CLASS", pci);
if (!test_set(vendor_id, device_id, class_id, pci, vmid, assigned))
{
return false;
}
}
return true;
}
/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/
void HostSharePCI::del(const vector<Attribute *> &devs)
{
vector<Attribute *>::const_iterator it;
map<string, PCIDevice *>::iterator pci_it;
for ( it=devs.begin(); it!= devs.end(); it++)
{
const VectorAttribute * pci = dynamic_cast<const VectorAttribute *>(*it);
if ( pci == 0 )
{
continue;
}
pci_it = pci_devices.find(pci->vector_value("ADDRESS"));
if (pci_it != pci_devices.end())
{
pci_it->second->vmid = -1;
pci_it->second->attrs->replace("VMID",-1);
}
}
};
/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/
void HostSharePCI::set_monitorization(vector<Attribute*> &pci_att)
{
vector<Attribute*>::iterator it;
map<string, PCIDevice*>::iterator pci_it;
string address;
for (it = pci_att.begin(); it != pci_att.end(); it++)
{
VectorAttribute * pci = dynamic_cast<VectorAttribute *>(*it);
if ( pci == 0 )
{
continue;
}
address = pci->vector_value("ADDRESS");
if (address.empty())
{
delete pci;
continue;
}
pci_it = pci_devices.find(address);
if (pci_it != pci_devices.end())
{
delete pci;
continue;
}
PCIDevice * dev = new PCIDevice(pci);
pci_devices.insert(make_pair(address, dev));
set(pci);
}
};
/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/
unsigned int HostSharePCI::get_pci_value(const char * name,
const VectorAttribute * pci_device)
{
string temp;
temp = pci_device->vector_value(name);
if (temp.empty())
{
return 0;
}
unsigned int pci_value;
istringstream iss(temp);
iss >> hex >> pci_value;
if (iss.fail() || !iss.eof())
{
return 0;
}
return pci_value;
}
HostSharePCI::PCIDevice::PCIDevice(VectorAttribute * _attrs)
: vmid(-1), attrs(_attrs)
{
vendor_id = get_pci_value("VENDOR", attrs);
device_id = get_pci_value("DEVICE", attrs);
class_id = get_pci_value("CLASS", attrs);
attrs->vector_value("VMID", vmid);
attrs->vector_value("ADDRESS", address);
};
/* ************************************************************************ */
/* HostShare :: Constructor/Destructor */
/* ************************************************************************ */
@ -42,8 +263,8 @@ HostShare::HostShare(long long _max_disk,long long _max_mem,long long _max_cpu):
used_mem(0),
used_cpu(0),
running_vms(0),
ds_template("DATASTORES"),
pci_template("PCI_DEVICES"){};
ds(),
pci(){};
ostream& operator<<(ostream& os, HostShare& hs)
{
@ -76,8 +297,8 @@ string& HostShare::to_xml(string& xml) const
<< "<USED_MEM>" << used_mem << "</USED_MEM>"
<< "<USED_CPU>" << used_cpu << "</USED_CPU>"
<< "<RUNNING_VMS>"<<running_vms <<"</RUNNING_VMS>"
<< ds_template.to_xml(ds_xml)
<< pci_template.to_xml(pci_xml)
<< ds.to_xml(ds_xml)
<< pci.to_xml(pci_xml)
<< "</HOST_SHARE>";
xml = oss.str();
@ -123,7 +344,7 @@ int HostShare::from_xml_node(const xmlNodePtr node)
return -1;
}
rc += ds_template.from_xml_node( content[0] );
rc += ds.from_xml_node( content[0] );
ObjectXML::free_nodes(content);
@ -143,7 +364,7 @@ int HostShare::from_xml_node(const xmlNodePtr node)
return -1;
}
rc += pci_template.from_xml_node( content[0] );
rc += pci.from_xml_node( content[0] );
ObjectXML::free_nodes(content);
@ -165,26 +386,14 @@ void HostShare::set_ds_monitorization(const vector<Attribute*> &ds_att)
{
vector<Attribute*>::const_iterator it;
ds_template.erase("DS");
ds.erase("DS");
for (it = ds_att.begin(); it != ds_att.end(); it++)
{
ds_template.set(*it);
ds.set(*it);
}
}
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
void HostShare::set_pci_monitorization(const vector<Attribute*> &pci_att)
{
vector<Attribute*>::const_iterator it;
pci_template.erase("PCI");
for (it = pci_att.begin(); it != pci_att.end(); it++)
{
pci_template.set(*it);
}
}