diff --git a/include/HostShare.h b/include/HostShare.h index 4d674e5d1e..9152b57b34 100644 --- a/include/HostShare.h +++ b/include/HostShare.h @@ -20,22 +20,149 @@ #include "ObjectXML.h" #include "Template.h" #include - -using namespace std; +#include /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ -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: + * + * : Three 4-hex digits groups representing :: + * : The corresponding device description + *
: PCI address, bus, slot and function + */ +class HostSharePCI : public Template +{ +public: + + HostSharePCI() : Template(false, '=', "PCI_DEVICES"){}; + + virtual ~HostSharePCI() + { + map::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 &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 &devs, int vmid) + { + test_set(devs, vmid); + } + + /** + * Remove the VM assigment from the PCI device list + */ + void del(const vector &devs); + + /** + * Updates the PCI list with monitor data, it will create or + * remove PCIDevices as needed. + */ + void set_monitorization(vector &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 &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 &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 pci_devices; +}; /** * The HostShare class. It represents a logical partition of a host... @@ -125,7 +252,10 @@ public: void set_ds_monitorization(const vector &ds_att); - void set_pci_monitorization(const vector &pci_att); + void set_pci_monitorization(vector &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 diff --git a/src/host/HostShare.cc b/src/host/HostShare.cc index 94d2850874..50525d7f16 100644 --- a/src/host/HostShare.cc +++ b/src/host/HostShare.cc @@ -15,7 +15,6 @@ /* ------------------------------------------------------------------------*/ #include -#include #include #include @@ -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 devices; + + int num_devs = get("PCI", devices); + + for (int i=0; i < num_devs; i++) + { + VectorAttribute * pci = dynamic_cast(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& assigned) +{ + map::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 &devs, int vmid) +{ + vector::iterator it; + std::set assigned; + + unsigned int vendor_id, device_id, class_id; + + for ( it=devs.begin(); it!= devs.end(); it++) + { + VectorAttribute * pci = dynamic_cast(*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 &devs) +{ + vector::const_iterator it; + map::iterator pci_it; + + for ( it=devs.begin(); it!= devs.end(); it++) + { + const VectorAttribute * pci = dynamic_cast(*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 &pci_att) +{ + vector::iterator it; + map::iterator pci_it; + + string address; + + for (it = pci_att.begin(); it != pci_att.end(); it++) + { + VectorAttribute * pci = dynamic_cast(*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_cpu << "" << ""<" - << ds_template.to_xml(ds_xml) - << pci_template.to_xml(pci_xml) + << ds.to_xml(ds_xml) + << pci.to_xml(pci_xml) << ""; 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 &ds_att) { vector::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 &pci_att) -{ - vector::const_iterator it; - - pci_template.erase("PCI"); - - for (it = pci_att.begin(); it != pci_att.end(); it++) - { - pci_template.set(*it); - } -} -