diff --git a/scripts/Makefile b/scripts/Makefile index a6afb71ab2b..020cbbeff49 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -135,7 +135,6 @@ install: $(IPROG) plugins/perfmon $(DESTDIR)$(PLUGINDIR) $(IPROG) plugins/extauth-hook $(DESTDIR)$(PLUGINDIR) $(IPROG) plugins/extauth-hook-AD.py $(DESTDIR)$(PLUGINDIR) - $(IPROG) plugins/iovirt $(DESTDIR)$(PLUGINDIR) $(IPROG) plugins/install-supp-pack $(DESTDIR)$(PLUGINDIR) $(IPROG) plugins/disk-space $(DESTDIR)$(PLUGINDIR) $(IPROG) plugins/firewall-port $(DESTDIR)$(PLUGINDIR) diff --git a/scripts/plugins/iovirt b/scripts/plugins/iovirt deleted file mode 100755 index c70c9a007fa..00000000000 --- a/scripts/plugins/iovirt +++ /dev/null @@ -1,848 +0,0 @@ -#!/usr/bin/env python -# -# THIS IS AN EXPERIMENTAL, UNSUPPORTED PLUGIN FOR DEMONSTRATION AND TEST ONLY. -# PLEASE DO NOT USE IT FOR PRODUCTION ENVIRONMENTS. -# THIS PLUGIN CAN BE REMOVED OR MODIFIED AT ANY TIME WITHOUT PREVIOUS WARNING. -# -# A plugin for managing IO virtualization including SR-IOV -# -# Each VM has pass-through VFs configured using the "pci" and "sriovmacs" -# other-config keys. Each of these is a comma separated list of entries -# of the form "/" for pci and "/" for sriovmacs - - -import XenAPI, inventory -import XenAPIPlugin -import os -import os.path -import stat -import glob -import re -import random -import subprocess -import xml.dom.minidom -import syslog - -ipcmd = "/sbin/ip" -hookscripts = ["/etc/xapi.d/vm-pre-start/vm-pre-start-iovirt", - "/etc/xapi.d/vm-pre-reboot/vm-pre-reboot-iovirt" -] - -re_virtfn = re.compile("virtfn(\d+)$") -re_netdev = re.compile("(eth\d+)$") -re_hex16 = re.compile("^[0-9a-f]{4}$") -re_hex16x = re.compile("^0x([0-9a-f]{4})$") - -def _install_hook_script(): - # Ensure that the hook script(s) used to configure SR-IOV VF MAC and - # VLANs is present. If the script isn't present create it. This - # function will be called whenever a VF is assigned. The intention - # is that the hook is not used for users not using this plugin because - # the additional API calls will add a small overhead to the VM.start - # time which may hurt some use cases. - for hookscript in hookscripts: - if os.path.exists(hookscript): - continue - syslog.syslog("Creating iovirt hook script at %s" % (hookscript)) - hookdir = os.path.dirname(hookscript) - if not os.path.exists(hookdir): - os.makedirs(hookdir) - f = file(hookscript, "w") - f.write("""#!/bin/bash -# -# Call the iovirt plugin to set up SR-IOV VF MAC and VLAN config -# if required for this VF. - -PLUGIN=iovirt -FN=prep_for_vm - -for i -do - case "$i" in - -vmuuid) shift; VMUUID=$1; shift;; - esac -done - -if [ -z "$VMUUID" ]; then - logger -t $(basename $0) "VM UUID not found in args" -fi - -. @INVENTORY@ - -if [ -z "$INSTALLATION_UUID" ]; then - logger -t $(basename $0) "Could not determine host UUID" -fi - -xe host-call-plugin plugin=$PLUGIN fn=$FN host-uuid=$INSTALLATION_UUID args:uuid=$VMUUID -""" - ) - f.close() - os.chmod(hookscript, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH) - -def _get_vfs(): - # Find PCI devices with virtfns, find all virtfns associated with - # network devices. Return dictionary of pciid => (vf#, ethdev) - vfnodes = glob.glob("/sys/bus/pci/devices/*/virtfn*") - vflist = {} - for vfnode in vfnodes: - vfpciid = os.path.basename(os.readlink(vfnode)) - r = re_virtfn.search(vfnode) - if not r: - raise "Failed to parse VF number for %s" % (vfnode) - vfnum = r.group(1) - netdevs = glob.glob("%s/physfn/net/eth*" % (vfnode)) - if len(netdevs) != 1: - raise "Unexpected length of netdev list for %s: %s" % (vfnode, str(netdevs)) - r = re_netdev.search(netdevs[0]) - if not r: - raise "Error parsing %s for net device" % (netdevs[0]) - netdev = r.group(1) - vflist[vfpciid] = (vfnum, netdev) - return vflist - -def _get_devices(vendorid, deviceid): - # Return device instances with the specified vendorid:deviceid - # Returns a dictionary of pciid => (vendorid, deviceid) - # Used for managing the assignment of non-SRIOV pools of devices. - if not re_hex16.match(vendorid): - raise "PCI vendor ID '%s' not in expected format" % (vendorid) - if not re_hex16.match(deviceid): - raise "PCI device ID '%s' not in expected format" % (deviceid) - devices = {} - devnodes = glob.glob("/sys/bus/pci/devices/*") - for devnode in devnodes: - pciid = os.path.basename(devnode) - vendor, device = _get_vendor_and_device_ids(pciid) - if vendor == vendorid and device == deviceid: - devices[pciid] = (vendor, device) - return devices - -def _get_vendor_and_device_ids(pciid): - devnode = ("/sys/bus/pci/devices/%s" % (pciid)) - vendor = None - device = None - if os.path.exists("%s/vendor" % (devnode)): - f = file("%s/vendor" % (devnode)) - d = f.read() - f.close() - vendorid = re_hex16x.search(d) - if vendorid: - vendor = vendorid.group(1) - if os.path.exists("%s/device" % (devnode)): - f = file("%s/device" % (devnode)) - d = f.read() - f.close() - deviceid = re_hex16x.search(d) - if deviceid: - device = deviceid.group(1) - return vendor, device - -def _get_assignments(session): - # Return a dict of PCI devices assigned to VMs. This currently assumes - # a pool of one host. In a pool this will be overly restrictive (i.e. - # a VM started on another host will be reported as having one of our - # host's devices) but it'll do for now. - # Returns a dictionary PCIID => (VMUUID, index, vendorid, deviceid, mac, vlan) - # where mac and vlan are only (optionally) available for SR-IOV VFs. - expr = 'field "is_a_template" = "false" and field "is_a_snapshot" = "false"' - vms = session.xenapi.VM.get_all_records_where(expr) - devices = {} - for vm in vms.values(): - # Ignore VMs with no PCI passthrough config or an empty config - if 'pci' not in vm['other_config']: - continue - if not vm['other_config']['pci']: - continue - vmuuid = vm['uuid'] - assignments = _get_vm_assignments(session, vmuuid) - for index in assignments.keys(): - devices[assignments[index][0]] = (vmuuid, - index, - assignments[index][1], - assignments[index][2], - assignments[index][3], - assignments[index][4]) - return devices - -def enable_iommu(session, args): - rc = os.system("@OPTDIR@/libexec/xen-cmdline --set-xen iommu=1") - return str(rc == 0) - -#def list_assigned_vfs(session, args): -# """List VFs on this host that are assigned to VMs that can run here.""" -# x = _get_assignments(session) -# return `x` - -def _get_vm_assignments(session, vmuuid): - # Return a dictionary of index => (PCIID, vendorid, deviceid, MAC, VLAN) - # for assignments for the specified VM. - # This includes SR-IOV NIC VFs and other PCI pass through - # devices. (MAC and VLAN only includes for the former) - re_pci = re.compile("^(\d+)/([0-9a-f:\.]+)$") - re_vlan = re.compile("^(\d+)/([0-9]+)$") - re_mac = re.compile("^(\d+)/([0-9a-fA-F:]+)$") - - vmref = session.xenapi.VM.get_by_uuid(vmuuid) - vm = session.xenapi.VM.get_record(vmref) - assignments = {} - - # Parse the SR-IOV MAC config string - macs = {} - if 'sriovmacs' in vm['other_config'] and vm['other_config']['sriovmacs']: - for x in vm['other_config']['sriovmacs'].split(","): - r = re_mac.search(x) - if not r: - raise Exception("Failed to parse MAC config '%s' for VM %s" % (x, vmuuid)) - macs[int(r.group(1))] = r.group(2) - - # Parse the SR-IOV VLAN config string - vlans = {} - if 'sriovvlans' in vm['other_config'] and vm['other_config']['sriovvlans']: - for x in vm['other_config']['sriovvlans'].split(","): - r = re_vlan.search(x) - if not r: - raise Exception("Failed to parse VLAN config '%s' for VM %s" % (x, vmuuid)) - vlans[int(r.group(1))] = r.group(2) - - # Parse the PCI config string - if 'pci' in vm['other_config'] and vm['other_config']['pci']: - for x in vm['other_config']['pci'].split(","): - r = re_pci.search(x) - if not r: - raise Exception("Failed to parse PCI config '%s' for VM %s" % (x, vmuuid)) - vendorid, deviceid = _get_vendor_and_device_ids(r.group(2)) - if int(r.group(1)) in macs: - mac = macs[int(r.group(1))] - else: - mac = None - if int(r.group(1)) in vlans: - vlan = vlans[int(r.group(1))] - else: - vlan = None - assignments[int(r.group(1))] = (r.group(2), vendorid, deviceid, mac, vlan) - - return assignments - -def _randomMAC(): - """Return a random MAC in the locally administered range""" - o1 = (random.randint(0, 63) << 2) | 2 - o2 = random.randint(0, 255) - o3 = random.randint(0, 255) - o4 = random.randint(0, 255) - o5 = random.randint(0, 255) - o6 = random.randint(0, 255) - return "%02x:%02x:%02x:%02x:%02x:%02x" % (o1, o2, o3, o4, o5, o6) - -def _set_vm_assignments(session, vmuuid, assignments): - # Set the PCI (and MAC and VLAN for SR-IOV) assignments for the - # specified VM removing any existing config first. assignments is a - # dictionary index => (pciid, vendorid, deviceid, mac, vlan) where - # vendorid and deviceid need not be set. - indexlist = assignments.keys() - indexlist.sort() - pcilist = [] - maclist = [] - vlanlist = [] - for i in indexlist: - pcilist.append("%u/%s" % (i, assignments[i][0])) - if assignments[i][3]: - maclist.append("%u/%s" % (i, assignments[i][3])) - if assignments[i][4]: - vlanlist.append("%u/%s" % (i, assignments[i][4])) - pci = ",".join(pcilist) - mac = ",".join(maclist) - vlan = ",".join(vlanlist) - vmref = session.xenapi.VM.get_by_uuid(vmuuid) - try: - session.xenapi.VM.remove_from_other_config(vmref, "pci") - except: - pass - try: - session.xenapi.VM.remove_from_other_config(vmref, "sriovmacs") - except: - pass - try: - session.xenapi.VM.remove_from_other_config(vmref, "sriovvlans") - except: - pass - if len(pci) > 0: - session.xenapi.VM.add_to_other_config(vmref, "pci", pci) - if len(mac) > 0: - session.xenapi.VM.add_to_other_config(vmref, "sriovmacs", mac) - if len(vlan) > 0: - session.xenapi.VM.add_to_other_config(vmref, "sriovvlans", vlan) - -def assign_free_vf(session, args): - """Assign a free VF on this host to the specified VM.""" - - # Ensure the hook script exists to configure VFs before VM.start - _install_hook_script() - - assigned = _get_assignments(session) - vfs = _get_vfs() - for vfid in assigned.keys(): - if vfid in vfs: - del vfs[vfid] - if "uuid" not in args: - raise "No VM UUID specified, please use the 'uuid' argument" - vmuuid = args["uuid"] - ethdev = None - vlan = None - pifref = None - - # Allow the caller to specify a the eth device from which the VF should - # be allocated - if "ethdev" in args: - ethdev = args["ethdev"] - - # Specify by network UUID. If this is a VLAN network then this forces the - # specification of a VLAN tag for the VF. - if "nwuuid" in args: - nwuuid = args["nwuuid"] - nwref = session.xenapi.network.get_by_uuid(nwuuid) - pifrefs = session.xenapi.network.get_PIFs(nwref) - # Find PIF for this host - hostuuid = inventory.get_localhost_uuid() - hostref = session.xenapi.host.get_by_uuid(hostuuid) - for pref in pifrefs: - if session.xenapi.PIF.get_host(pref) == hostref: - pifref = pref - break - if not pifref: - raise "Could not find PIF record for network %s on this host" % (nwuuid) - - # Specify by PIF UUID. If this is a VLAN PIF then this forces the - # specification of a VLAN tag for the VF. - if "pifuuid" in args: - pifuuid = args["pifuuid"] - pifref = session.xenapi.PIF.get_by_uuid(pifuuid) - - if pifref: - v = str(session.xenapi.PIF.get_VLAN(pifref)) - if v and v != "-1": - vlan = v - ethdev = session.xenapi.PIF.get_device(pifref) - - # If no ethdev, PIF or network is specified then reject - if not ethdev: - raise "Must specify eth device by device, PIF or network." - - # If the caller specified a pass through index use that otherwise - # find the first one not currently configured. - ourassignments = _get_vm_assignments(session, vmuuid) - if "index" in args: - index = int(args["index"]) - else: - i = 0 - while True: - if not i in ourassignments.keys(): - index = i - break - i = i + 1 - - # Use the user specified MAC or create a local adminstered one - if "mac" in args: - mac = args["mac"] - else: - mac = _randomMAC() - - if "vlan" in args: - if vlan and args["vlan"] != vlan: - raise "Cannot override PIF VLAN %s" % (vlan) - vlan = args["vlan"] - - # Choose a suitable VF. Preference is for lower numbered VFs - revdict = {} - for vfid in vfs.keys(): - rvf, rdev = vfs[vfid] - rkey = "%08u%s" % (int(rvf), rdev) - revdict[rkey] = vfid - revdictkeys = revdict.keys() - revdictkeys.sort() - vfidlist = [revdict[x] for x in revdictkeys] - myid = None - for vfid in vfidlist: - if not ethdev: - myid = vfid - break - if ethdev == vfs[vfid][1]: - myid = vfid - break - if not myid: - if ethdev: - raise "No spare VF on %s" % (ethdev) - raise "No spare VF" - - # Set up the config for the VM. No need to fill out the vendor and - # device id fields for this. - ourassignments[index] = (myid, None, None, mac, vlan) - _set_vm_assignments(session, vmuuid, ourassignments) - - vfnum, vfeth = vfs[myid] - - dom = xml.dom.minidom.Document() - element = dom.createElement("iovirt") - dom.appendChild(element) - - entry = dom.createElement("vf") - element.appendChild(entry) - - subentry = dom.createElement("pciid") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(myid)) - - subentry = dom.createElement("device") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vfeth)) - - subentry = dom.createElement("vfnum") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vfnum)) - - if mac: - subentry = dom.createElement("mac") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(mac)) - if vlan: - subentry = dom.createElement("vlan") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vlan)) - - aentry = dom.createElement("assigned") - entry.appendChild(aentry) - - subentry = dom.createElement("vm") - aentry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vmuuid)) - - subentry = dom.createElement("index") - aentry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(str(index))) - - return dom.toprettyxml() - -def unassign_vf(session, args, genericpci=False): - """Unassign a VF/device from a VM.""" - if "uuid" not in args: - raise "No VM UUID specified, please use the 'uuid' argument" - vmuuid = args["uuid"] - - # Specify the VF/device by either PCI ID, index, or ethX+VFn - pciid = None - index = None - vfdisplay = "" - if "index" in args: - index = int(args["index"]) - if "pciid" in args: - pciid = args["pciid"] - vfdisplay = pciid - if "ethdev" in args and "vf" in args and not genericpci: - ethdev = args["ethdev"] - vfnum = args["vf"] - vfdisplay = "%s VF %s" % (ethdev, vfnum) - vfs = _get_vfs() - for vfpciid in vfs.keys(): - if (vfnum, ethdev) == vfs[vfpciid]: - pciid = vfpciid - break - if not pciid: - raise "Unable to find PCI ID for " + vfdisplay - - if not pciid and index == None: - if genericpci: - raise "Need to specify either a pciid or index" - else: - raise "Need to specify either a pciid, index or ethdev and vf" - - # Current assignments - current = _get_vm_assignments(session, vmuuid) - - # Remove the specified ID - if pciid: - if not pciid in [x[0] for x in current.values()]: - raise "VM %s does not have %s assigned" % (vmuuid, vfdisplay) - for i in current.keys(): - if current[i][0] == pciid: - del current[i] - else: - if index not in current: - raise "VM %s does not have PCI passthrough index %u" % (index) - del current[index] - - # Update the config - _set_vm_assignments(session, vmuuid, current) - return "" - -def assign_free_pci_device(session, args): - """Assign a free PCI device on this host to the specified VM.""" - assigned = _get_assignments(session) - if "vendorid" not in args: - raise "No vendor ID specified, please use the 'vendorid' argument" - if "deviceid" not in args: - raise "No device ID specified, please use the 'deviceid' argument" - # _get_devices will check syntax of the args - vendorid = args["vendorid"] - deviceid = args["deviceid"] - devices = _get_devices(vendorid, deviceid) - - for pciid in assigned.keys(): - if pciid in devices: - del devices[pciid] - if "uuid" not in args: - raise "No VM UUID specified, please use the 'uuid' argument" - vmuuid = args["uuid"] - - # If the caller specified a pass through index use that otherwise - # find the first one not currently configured. - ourassignments = _get_vm_assignments(session, vmuuid) - if "index" in args: - index = int(args["index"]) - else: - i = 0 - while True: - if not i in ourassignments.keys(): - index = i - break - i = i + 1 - - # Choose a suitable device. Preference is for lower numbered PCIIDs - pciids = devices.keys() - pciids.sort() - myid = None - if len(pciids) > 0: - myid = pciids[0] - if not myid: - raise "No spare %s:%s device" % (vendorid, deviceid) - - # Set up the config for the VM. No need to fill out the vendor and - # device id fields for this. - ourassignments[index] = (myid, None, None, None, None) - _set_vm_assignments(session, vmuuid, ourassignments) - - dom = xml.dom.minidom.Document() - element = dom.createElement("iovirt") - dom.appendChild(element) - - entry = dom.createElement("pcidevice") - element.appendChild(entry) - - subentry = dom.createElement("pciid") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(myid)) - - subentry = dom.createElement("vendorid") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vendorid)) - - subentry = dom.createElement("deviceid") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(deviceid)) - - aentry = dom.createElement("assigned") - entry.appendChild(aentry) - - subentry = dom.createElement("vm") - aentry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vmuuid)) - - subentry = dom.createElement("index") - aentry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(str(index))) - - return dom.toprettyxml() - -def unassign_pci_device(session, args): - return unassign_vf(session, args, genericpci=True) - -def show_summary(session, args): - """Return a textual summary of SR-IOV configuarion of this host.""" - assigned = _get_assignments(session) - vfs = _get_vfs() - vfids = vfs.keys() - vfids.sort() - dom = xml.dom.minidom.Document() - element = dom.createElement("iovirt") - dom.appendChild(element) - - for vfid in vfids: - entry = dom.createElement("vf") - element.appendChild(entry) - - vfnum, vfeth = vfs[vfid] - - subentry = dom.createElement("pciid") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vfid)) - - subentry = dom.createElement("device") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vfeth)) - - subentry = dom.createElement("vfnum") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vfnum)) - - if vfid in assigned: - vmuuid, vmnum, vendorid, deviceid, mac, vlan = assigned[vfid] - aentry = dom.createElement("assigned") - entry.appendChild(aentry) - - subentry = dom.createElement("vm") - aentry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vmuuid)) - - subentry = dom.createElement("index") - aentry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(str(vmnum))) - - # MAC and VLAN go in the parent node - if mac: - subentry = dom.createElement("mac") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(mac)) - if vlan: - subentry = dom.createElement("vlan") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vlan)) - - return dom.toprettyxml() - -def list_pci_devices(session, args): - """Return a list of PCI devices of the specified vendorid:deviceid and their assignments.""" - if "vendorid" not in args: - raise "No vendor ID specified, please use the 'vendorid' argument" - if "deviceid" not in args: - raise "No device ID specified, please use the 'deviceid' argument" - # _get_devices will check syntax of the args - vendorid = args["vendorid"] - deviceid = args["deviceid"] - devices = _get_devices(vendorid, deviceid) - assigned = _get_assignments(session) - pciids = devices.keys() - pciids.sort() - dom = xml.dom.minidom.Document() - element = dom.createElement("iovirt") - dom.appendChild(element) - for pciid in pciids: - entry = dom.createElement("pcidevice") - element.appendChild(entry) - - subentry = dom.createElement("pciid") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(pciid)) - - subentry = dom.createElement("vendorid") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vendorid)) - - subentry = dom.createElement("deviceid") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(deviceid)) - - if pciid in assigned: - vmuuid, vmnum, vendorid, deviceid, mac, vlan = assigned[pciid] - aentry = dom.createElement("assigned") - entry.appendChild(aentry) - - subentry = dom.createElement("vm") - aentry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vmuuid)) - - subentry = dom.createElement("index") - aentry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(str(vmnum))) - - if mac: - subentry = dom.createElement("mac") - aentry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(mac)) - if vlan: - subentry = dom.createElement("vlan") - aentry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vlan)) - - return dom.toprettyxml() - -def get_vm(session, args): - """Return a description of the SR-IOV config for the specified VM.""" - if "uuid" not in args: - raise "No VM UUID specified, please use the 'uuid' argument" - vmuuid = args["uuid"] - vfs = _get_vfs() - current = _get_vm_assignments(session, vmuuid) - indexlist = current.keys() - indexlist.sort() - dom = xml.dom.minidom.Document() - element = dom.createElement("iovirt") - dom.appendChild(element) - vmentry = dom.createElement("vm") - element.appendChild(vmentry) - subentry = dom.createElement("uuid") - vmentry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vmuuid)) - for i in indexlist: - entry = dom.createElement("passthrough") - vmentry.appendChild(entry) - subentry = dom.createElement("index") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(str(i))) - - pciid, vendorid, deviceid, mac, vlan = current[i] - - subentry = dom.createElement("pciid") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(pciid)) - subentry = dom.createElement("vendorid") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vendorid)) - subentry = dom.createElement("deviceid") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(deviceid)) - if mac: - subentry = dom.createElement("mac") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(mac)) - if vlan: - subentry = dom.createElement("vlan") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vlan)) - if pciid in vfs: - vfnum, ethdev = vfs[pciid] - subentry = dom.createElement("vfnum") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(vfnum)) - subentry = dom.createElement("device") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode(ethdev)) - subentry = dom.createElement("pttype") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode("vf")) - else: - subentry = dom.createElement("pttype") - entry.appendChild(subentry) - subentry.appendChild(dom.createTextNode("pcidevice")) - return dom.toprettyxml() - -def prep_for_vm(session, args): - if "uuid" not in args: - raise "No VM UUID specified, please use the 'uuid' argument" - vmuuid = args["uuid"] - current = _get_vm_assignments(session, vmuuid) - vfs = _get_vfs() - reply = [] - for i in current.keys(): - pciid, vendorid, deviceid, mac, vlan = current[i] - if not pciid in vfs.keys(): - # This is probably a non SR-IOV PCI device being passed - # through. Log that we cannot find details and carry on - # processing the device list. - syslog.syslog("Could not find VF details for %s for %s, assume it is a non SR-IOV passthrough" % (pciid, vmuuid)) - continue - vfnum, ethdev = vfs[pciid] - if mac: - # Check MAC really is a MAC - if not re.match("^([0-9a-fA-F:]+)$", mac): - raise "Unexpected MAC text '%s' for VM %s" % (mac, vmuuid) - cmd = "%s link set %s vf %s mac %s" % (ipcmd, ethdev, vfnum, mac) - reply.append(cmd) - syslog.syslog("Setting VF MAC with '%s' for VM %s" % (cmd, vmuuid)) - os.system(cmd) - if not vlan: - # No VLAN may need explicit clearly of previously assigned VLAN - vlan = "0" - # Check VLAN really is an integer - if not re.match("^\d+$", vlan): - raise "Unexpected VLAN text '%s' for VM %s" % (vlan, vmuuid) - cmd2 = "%s link set %s vf %s vlan %s" % (ipcmd, ethdev, vfnum, vlan) - reply.append(cmd2) - syslog.syslog("Setting VF VLAN with '%s' for VM %s" % (cmd, vmuuid)) - os.system(cmd2) - return "\n".join(reply) - -def unassign_all(session, args): - """Clear all SR-IOV and PCI passthrough devices from a VM.""" - if "uuid" not in args: - raise "No VM UUID specified, please use the 'uuid' argument" - vmuuid = args["uuid"] - - # Update the config - _set_vm_assignments(session, vmuuid, {}) - return "" - -def change_vf_mac(session, args): - """Change the MAC address for a VF already assigned to a VM.""" - - if "mac" not in args: - raise "Need to specify a new MAC address" - mac = args["mac"] - - if "uuid" not in args: - raise "No VM UUID specified, please use the 'uuid' argument" - vmuuid = args["uuid"] - - # Specify the VF by index - if "index" not in args: - raise "Need to specify the VF index" - index = int(args["index"]) - - # Current assignments - current = _get_vm_assignments(session, vmuuid) - - # Update the MAC - if index not in current: - raise "VF index %u not found for VM %s" % (index, vmuuid) - c = current[index] - current[index] = (c[0], c[1], c[2], mac, c[4]) - - # Update the config - _set_vm_assignments(session, vmuuid, current) - - return "" - -def change_vf_vlan(session, args): - """Change the VLAN for a VF already assigned to a VM. - Use vlan=None to remove VLAN tagging.""" - - if "vlan" not in args: - raise "Need to specify a new VLAN" - vlan = args["vlan"] - if vlan.lower() == "none": - vlan = None - - if "uuid" not in args: - raise "No VM UUID specified, please use the 'uuid' argument" - vmuuid = args["uuid"] - - # Specify the VF by index - if "index" not in args: - raise "Need to specify the VF index" - index = int(args["index"]) - - # Current assignments - current = _get_vm_assignments(session, vmuuid) - - # Update the MAC - if index not in current: - raise "VF index %u not found for VM %s" % (index, vmuuid) - c = current[index] - current[index] = (c[0], c[1], c[2], c[3], vlan) - - # Update the config - _set_vm_assignments(session, vmuuid, current) - - return "" - -if __name__ == "__main__": - XenAPIPlugin.dispatch({"enable_iommu": enable_iommu, - "assign_free_vf": assign_free_vf, - "show_summary": show_summary, - "unassign_vf": unassign_vf, - "assign_free_pci_device": assign_free_pci_device, - "unassign_pci_device": unassign_pci_device, - "get_vm": get_vm, - "prep_for_vm": prep_for_vm, - "list_pci_devices": list_pci_devices, - "unassign_all": unassign_all, - "change_vf_vlan": change_vf_vlan, - "change_vf_mac": change_vf_mac}) -