3
# THIS IS AN EXPERIMENTAL, UNSUPPORTED PLUGIN FOR DEMONSTRATION AND TEST ONLY.
4
# PLEASE DO NOT USE IT FOR PRODUCTION ENVIRONMENTS.
5
# THIS PLUGIN CAN BE REMOVED OR MODIFIED AT ANY TIME WITHOUT PREVIOUS WARNING.
7
# A plugin for managing IO virtualization including SR-IOV
9
# Each VM has pass-through VFs configured using the "pci" and "sriovmacs"
10
# other-config keys. Each of these is a comma separated list of entries
11
# of the form "<index>/<pciid>" for pci and "<index>/<mac>" for sriovmacs
14
import XenAPI, inventory
23
import xml.dom.minidom
27
hookscripts = ["/etc/xapi.d/vm-pre-start/vm-pre-start-iovirt",
28
"/etc/xapi.d/vm-pre-reboot/vm-pre-reboot-iovirt"
31
re_virtfn = re.compile("virtfn(\d+)$")
32
re_netdev = re.compile("(eth\d+)$")
33
re_hex16 = re.compile("^[0-9a-f]{4}$")
34
re_hex16x = re.compile("^0x([0-9a-f]{4})$")
36
def _install_hook_script():
37
# Ensure that the hook script(s) used to configure SR-IOV VF MAC and
38
# VLANs is present. If the script isn't present create it. This
39
# function will be called whenever a VF is assigned. The intention
40
# is that the hook is not used for users not using this plugin because
41
# the additional API calls will add a small overhead to the VM.start
42
# time which may hurt some use cases.
43
for hookscript in hookscripts:
44
if os.path.exists(hookscript):
46
syslog.syslog("Creating iovirt hook script at %s" % (hookscript))
47
hookdir = os.path.dirname(hookscript)
48
if not os.path.exists(hookdir):
50
f = file(hookscript, "w")
51
f.write("""#!/bin/bash
53
# Call the iovirt plugin to set up SR-IOV VF MAC and VLAN config
54
# if required for this VF.
62
-vmuuid) shift; VMUUID=$1; shift;;
66
if [ -z "$VMUUID" ]; then
67
logger -t $(basename $0) "VM UUID not found in args"
70
. /etc/xensource-inventory
72
if [ -z "$INSTALLATION_UUID" ]; then
73
logger -t $(basename $0) "Could not determine host UUID"
76
xe host-call-plugin plugin=$PLUGIN fn=$FN host-uuid=$INSTALLATION_UUID args:uuid=$VMUUID
80
os.chmod(hookscript, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
83
# Find PCI devices with virtfns, find all virtfns associated with
84
# network devices. Return dictionary of pciid => (vf#, ethdev)
85
vfnodes = glob.glob("/sys/bus/pci/devices/*/virtfn*")
87
for vfnode in vfnodes:
88
vfpciid = os.path.basename(os.readlink(vfnode))
89
r = re_virtfn.search(vfnode)
91
raise "Failed to parse VF number for %s" % (vfnode)
93
netdevs = glob.glob("%s/physfn/net:eth*" % (vfnode))
95
raise "Unexpected length of netdev list for %s: %s" % (vfnode, str(netdevs))
96
r = re_netdev.search(netdevs[0])
98
raise "Error parsing %s for net device" % (netdevs[0])
100
vflist[vfpciid] = (vfnum, netdev)
103
def _get_devices(vendorid, deviceid):
104
# Return device instances with the specified vendorid:deviceid
105
# Returns a dictionary of pciid => (vendorid, deviceid)
106
# Used for managing the assignment of non-SRIOV pools of devices.
107
if not re_hex16.match(vendorid):
108
raise "PCI vendor ID '%s' not in expected format" % (vendorid)
109
if not re_hex16.match(deviceid):
110
raise "PCI device ID '%s' not in expected format" % (deviceid)
112
devnodes = glob.glob("/sys/bus/pci/devices/*")
113
for devnode in devnodes:
114
pciid = os.path.basename(devnode)
115
vendor, device = _get_vendor_and_device_ids(pciid)
116
if vendor == vendorid and device == deviceid:
117
devices[pciid] = (vendor, device)
120
def _get_vendor_and_device_ids(pciid):
121
devnode = ("/sys/bus/pci/devices/%s" % (pciid))
124
if os.path.exists("%s/vendor" % (devnode)):
125
f = file("%s/vendor" % (devnode))
128
vendorid = re_hex16x.search(d)
130
vendor = vendorid.group(1)
131
if os.path.exists("%s/device" % (devnode)):
132
f = file("%s/device" % (devnode))
135
deviceid = re_hex16x.search(d)
137
device = deviceid.group(1)
138
return vendor, device
140
def _get_assignments(session):
141
# Return a dict of PCI devices assigned to VMs. This currently assumes
142
# a pool of one host. In a pool this will be overly restrictive (i.e.
143
# a VM started on another host will be reported as having one of our
144
# host's devices) but it'll do for now.
145
# Returns a dictionary PCIID => (VMUUID, index, vendorid, deviceid, mac, vlan)
146
# where mac and vlan are only (optionally) available for SR-IOV VFs.
147
expr = 'field "is_a_template" = "false" and field "is_a_snapshot" = "false"'
148
vms = session.xenapi.VM.get_all_records_where(expr)
150
for vm in vms.values():
151
# Ignore VMs with no PCI passthrough config or an empty config
152
if not vm['other_config'].has_key('pci'):
154
if not vm['other_config']['pci']:
157
assignments = _get_vm_assignments(session, vmuuid)
158
for index in assignments.keys():
159
devices[assignments[index][0]] = (vmuuid,
161
assignments[index][1],
162
assignments[index][2],
163
assignments[index][3],
164
assignments[index][4])
167
def enable_iommu(session, args):
168
rc = os.system("@BASE_PATH@/libexec/xen-cmdline --set-xen iommu=1")
171
#def list_assigned_vfs(session, args):
172
# """List VFs on this host that are assigned to VMs that can run here."""
173
# x = _get_assignments(session)
176
def _get_vm_assignments(session, vmuuid):
177
# Return a dictionary of index => (PCIID, vendorid, deviceid, MAC, VLAN)
178
# for assignments for the specified VM.
179
# This includes SR-IOV NIC VFs and other PCI pass through
180
# devices. (MAC and VLAN only includes for the former)
181
re_pci = re.compile("^(\d+)/([0-9a-f:\.]+)$")
182
re_vlan = re.compile("^(\d+)/([0-9]+)$")
183
re_mac = re.compile("^(\d+)/([0-9a-fA-F:]+)$")
185
vmref = session.xenapi.VM.get_by_uuid(vmuuid)
186
vm = session.xenapi.VM.get_record(vmref)
189
# Parse the SR-IOV MAC config string
191
if vm['other_config'].has_key('sriovmacs') and vm['other_config']['sriovmacs']:
192
for x in vm['other_config']['sriovmacs'].split(","):
195
raise "Failed to parse MAC config '%s' for VM %s" % x, vmuuid
196
macs[int(r.group(1))] = r.group(2)
198
# Parse the SR-IOV VLAN config string
200
if vm['other_config'].has_key('sriovvlans') and vm['other_config']['sriovvlans']:
201
for x in vm['other_config']['sriovvlans'].split(","):
202
r = re_vlan.search(x)
204
raise "Failed to parse VLAN config '%s' for VM %s" % x, vmuuid
205
vlans[int(r.group(1))] = r.group(2)
207
# Parse the PCI config string
208
if vm['other_config'].has_key('pci') and vm['other_config']['pci']:
209
for x in vm['other_config']['pci'].split(","):
212
raise "Failed to parse PCI config '%s' for VM %s" % x, vmuuid
213
vendorid, deviceid = _get_vendor_and_device_ids(r.group(2))
214
if macs.has_key(int(r.group(1))):
215
mac = macs[int(r.group(1))]
218
if vlans.has_key(int(r.group(1))):
219
vlan = vlans[int(r.group(1))]
222
assignments[int(r.group(1))] = (r.group(2), vendorid, deviceid, mac, vlan)
227
"""Return a random MAC in the locally administered range"""
228
o1 = (random.randint(0, 63) << 2) | 2
229
o2 = random.randint(0, 255)
230
o3 = random.randint(0, 255)
231
o4 = random.randint(0, 255)
232
o5 = random.randint(0, 255)
233
o6 = random.randint(0, 255)
234
return "%02x:%02x:%02x:%02x:%02x:%02x" % (o1, o2, o3, o4, o5, o6)
236
def _set_vm_assignments(session, vmuuid, assignments):
237
# Set the PCI (and MAC and VLAN for SR-IOV) assignments for the
238
# specified VM removing any existing config first. assignments is a
239
# dictionary index => (pciid, vendorid, deviceid, mac, vlan) where
240
# vendorid and deviceid need not be set.
241
indexlist = assignments.keys()
247
pcilist.append("%u/%s" % (i, assignments[i][0]))
248
if assignments[i][3]:
249
maclist.append("%u/%s" % (i, assignments[i][3]))
250
if assignments[i][4]:
251
vlanlist.append("%u/%s" % (i, assignments[i][4]))
252
pci = ",".join(pcilist)
253
mac = ",".join(maclist)
254
vlan = ",".join(vlanlist)
255
vmref = session.xenapi.VM.get_by_uuid(vmuuid)
257
session.xenapi.VM.remove_from_other_config(vmref, "pci")
261
session.xenapi.VM.remove_from_other_config(vmref, "sriovmacs")
265
session.xenapi.VM.remove_from_other_config(vmref, "sriovvlans")
269
session.xenapi.VM.add_to_other_config(vmref, "pci", pci)
271
session.xenapi.VM.add_to_other_config(vmref, "sriovmacs", mac)
273
session.xenapi.VM.add_to_other_config(vmref, "sriovvlans", vlan)
275
def assign_free_vf(session, args):
276
"""Assign a free VF on this host to the specified VM."""
278
# Ensure the hook script exists to configure VFs before VM.start
279
_install_hook_script()
281
assigned = _get_assignments(session)
283
for vfid in assigned.keys():
286
if not args.has_key("uuid"):
287
raise "No VM UUID specified, please use the 'uuid' argument"
288
vmuuid = args["uuid"]
293
# Allow the caller to specify a the eth device from which the VF should
295
if args.has_key("ethdev"):
296
ethdev = args["ethdev"]
298
# Specify by network UUID. If this is a VLAN network then this forces the
299
# specification of a VLAN tag for the VF.
300
if args.has_key("nwuuid"):
301
nwuuid = args["nwuuid"]
302
nwref = session.xenapi.network.get_by_uuid(nwuuid)
303
pifrefs = session.xenapi.network.get_PIFs(nwref)
304
# Find PIF for this host
305
hostuuid = inventory.get_localhost_uuid()
306
hostref = session.xenapi.host.get_by_uuid(hostuuid)
308
if session.xenapi.PIF.get_host(pref) == hostref:
312
raise "Could not find PIF record for network %s on this host" % (nwuuid)
314
# Specify by PIF UUID. If this is a VLAN PIF then this forces the
315
# specification of a VLAN tag for the VF.
316
if args.has_key("pifuuid"):
317
pifuuid = args["pifuuid"]
318
pifref = session.xenapi.PIF.get_by_uuid(pifuuid)
321
v = str(session.xenapi.PIF.get_VLAN(pifref))
324
ethdev = session.xenapi.PIF.get_device(pifref)
326
# If no ethdev, PIF or network is specified then reject
328
raise "Must specify eth device by device, PIF or network."
330
# If the caller specified a pass through index use that otherwise
331
# find the first one not currently configured.
332
ourassignments = _get_vm_assignments(session, vmuuid)
333
if args.has_key("index"):
334
index = int(args["index"])
338
if not i in ourassignments.keys():
343
# Use the user specified MAC or create a local adminstered one
344
if args.has_key("mac"):
349
if args.has_key("vlan"):
350
if vlan and args["vlan"] != vlan:
351
raise "Cannot override PIF VLAN %s" % (vlan)
354
# Choose a suitable VF. Preference is for lower numbered VFs
356
for vfid in vfs.keys():
357
rvf, rdev = vfs[vfid]
358
rkey = "%08u%s" % (int(rvf), rdev)
360
revdictkeys = revdict.keys()
362
vfidlist = [revdict[x] for x in revdictkeys]
364
for vfid in vfidlist:
368
if ethdev == vfs[vfid][1]:
373
raise "No spare VF on %s" % (ethdev)
376
# Set up the config for the VM. No need to fill out the vendor and
377
# device id fields for this.
378
ourassignments[index] = (myid, None, None, mac, vlan)
379
_set_vm_assignments(session, vmuuid, ourassignments)
381
vfnum, vfeth = vfs[myid]
383
dom = xml.dom.minidom.Document()
384
element = dom.createElement("iovirt")
385
dom.appendChild(element)
387
entry = dom.createElement("vf")
388
element.appendChild(entry)
390
subentry = dom.createElement("pciid")
391
entry.appendChild(subentry)
392
subentry.appendChild(dom.createTextNode(myid))
394
subentry = dom.createElement("device")
395
entry.appendChild(subentry)
396
subentry.appendChild(dom.createTextNode(vfeth))
398
subentry = dom.createElement("vfnum")
399
entry.appendChild(subentry)
400
subentry.appendChild(dom.createTextNode(vfnum))
403
subentry = dom.createElement("mac")
404
entry.appendChild(subentry)
405
subentry.appendChild(dom.createTextNode(mac))
407
subentry = dom.createElement("vlan")
408
entry.appendChild(subentry)
409
subentry.appendChild(dom.createTextNode(vlan))
411
aentry = dom.createElement("assigned")
412
entry.appendChild(aentry)
414
subentry = dom.createElement("vm")
415
aentry.appendChild(subentry)
416
subentry.appendChild(dom.createTextNode(vmuuid))
418
subentry = dom.createElement("index")
419
aentry.appendChild(subentry)
420
subentry.appendChild(dom.createTextNode(str(index)))
422
return dom.toprettyxml()
424
def unassign_vf(session, args, genericpci=False):
425
"""Unassign a VF/device from a VM."""
426
if not args.has_key("uuid"):
427
raise "No VM UUID specified, please use the 'uuid' argument"
428
vmuuid = args["uuid"]
430
# Specify the VF/device by either PCI ID, index, or ethX+VFn
434
if args.has_key("index"):
435
index = int(args["index"])
436
if args.has_key("pciid"):
437
pciid = args["pciid"]
439
if args.has_key("ethdev") and args.has_key("vf") and not genericpci:
440
ethdev = args["ethdev"]
442
vfdisplay = "%s VF %s" % (ethdev, vfnum)
444
for vfpciid in vfs.keys():
445
if (vfnum, ethdev) == vfs[vfpciid]:
449
raise "Unable to find PCI ID for " + vfdisplay
451
if not pciid and index == None:
453
raise "Need to specify either a pciid or index"
455
raise "Need to specify either a pciid, index or ethdev and vf"
457
# Current assignments
458
current = _get_vm_assignments(session, vmuuid)
460
# Remove the specified ID
462
if not pciid in [x[0] for x in current.values()]:
463
raise "VM %s does not have %s assigned" % (vmuuid, vfdisplay)
464
for i in current.keys():
465
if current[i][0] == pciid:
468
if not current.has_key(index):
469
raise "VM %s does not have PCI passthrough index %u" % (index)
473
_set_vm_assignments(session, vmuuid, current)
476
def assign_free_pci_device(session, args):
477
"""Assign a free PCI device on this host to the specified VM."""
478
assigned = _get_assignments(session)
479
if not args.has_key("vendorid"):
480
raise "No vendor ID specified, please use the 'vendorid' argument"
481
if not args.has_key("deviceid"):
482
raise "No device ID specified, please use the 'deviceid' argument"
483
# _get_devices will check syntax of the args
484
vendorid = args["vendorid"]
485
deviceid = args["deviceid"]
486
devices = _get_devices(vendorid, deviceid)
488
for pciid in assigned.keys():
491
if not args.has_key("uuid"):
492
raise "No VM UUID specified, please use the 'uuid' argument"
493
vmuuid = args["uuid"]
495
# If the caller specified a pass through index use that otherwise
496
# find the first one not currently configured.
497
ourassignments = _get_vm_assignments(session, vmuuid)
498
if args.has_key("index"):
499
index = int(args["index"])
503
if not i in ourassignments.keys():
508
# Choose a suitable device. Preference is for lower numbered PCIIDs
509
pciids = devices.keys()
515
raise "No spare %s:%s device" % (vendorid, deviceid)
517
# Set up the config for the VM. No need to fill out the vendor and
518
# device id fields for this.
519
ourassignments[index] = (myid, None, None, None, None)
520
_set_vm_assignments(session, vmuuid, ourassignments)
522
dom = xml.dom.minidom.Document()
523
element = dom.createElement("iovirt")
524
dom.appendChild(element)
526
entry = dom.createElement("pcidevice")
527
element.appendChild(entry)
529
subentry = dom.createElement("pciid")
530
entry.appendChild(subentry)
531
subentry.appendChild(dom.createTextNode(myid))
533
subentry = dom.createElement("vendorid")
534
entry.appendChild(subentry)
535
subentry.appendChild(dom.createTextNode(vendorid))
537
subentry = dom.createElement("deviceid")
538
entry.appendChild(subentry)
539
subentry.appendChild(dom.createTextNode(deviceid))
541
aentry = dom.createElement("assigned")
542
entry.appendChild(aentry)
544
subentry = dom.createElement("vm")
545
aentry.appendChild(subentry)
546
subentry.appendChild(dom.createTextNode(vmuuid))
548
subentry = dom.createElement("index")
549
aentry.appendChild(subentry)
550
subentry.appendChild(dom.createTextNode(str(index)))
552
return dom.toprettyxml()
554
def unassign_pci_device(session, args):
555
return unassign_vf(session, args, genericpci=True)
557
def show_summary(session, args):
558
"""Return a textual summary of SR-IOV configuarion of this host."""
559
assigned = _get_assignments(session)
563
dom = xml.dom.minidom.Document()
564
element = dom.createElement("iovirt")
565
dom.appendChild(element)
568
entry = dom.createElement("vf")
569
element.appendChild(entry)
571
vfnum, vfeth = vfs[vfid]
573
subentry = dom.createElement("pciid")
574
entry.appendChild(subentry)
575
subentry.appendChild(dom.createTextNode(vfid))
577
subentry = dom.createElement("device")
578
entry.appendChild(subentry)
579
subentry.appendChild(dom.createTextNode(vfeth))
581
subentry = dom.createElement("vfnum")
582
entry.appendChild(subentry)
583
subentry.appendChild(dom.createTextNode(vfnum))
585
if assigned.has_key(vfid):
586
vmuuid, vmnum, vendorid, deviceid, mac, vlan = assigned[vfid]
587
aentry = dom.createElement("assigned")
588
entry.appendChild(aentry)
590
subentry = dom.createElement("vm")
591
aentry.appendChild(subentry)
592
subentry.appendChild(dom.createTextNode(vmuuid))
594
subentry = dom.createElement("index")
595
aentry.appendChild(subentry)
596
subentry.appendChild(dom.createTextNode(str(vmnum)))
598
# MAC and VLAN go in the parent node
600
subentry = dom.createElement("mac")
601
entry.appendChild(subentry)
602
subentry.appendChild(dom.createTextNode(mac))
604
subentry = dom.createElement("vlan")
605
entry.appendChild(subentry)
606
subentry.appendChild(dom.createTextNode(vlan))
608
return dom.toprettyxml()
610
def list_pci_devices(session, args):
611
"""Return a list of PCI devices of the specified vendorid:deviceid and their assignments."""
612
if not args.has_key("vendorid"):
613
raise "No vendor ID specified, please use the 'vendorid' argument"
614
if not args.has_key("deviceid"):
615
raise "No device ID specified, please use the 'deviceid' argument"
616
# _get_devices will check syntax of the args
617
vendorid = args["vendorid"]
618
deviceid = args["deviceid"]
619
devices = _get_devices(vendorid, deviceid)
620
assigned = _get_assignments(session)
621
pciids = devices.keys()
623
dom = xml.dom.minidom.Document()
624
element = dom.createElement("iovirt")
625
dom.appendChild(element)
627
entry = dom.createElement("pcidevice")
628
element.appendChild(entry)
630
subentry = dom.createElement("pciid")
631
entry.appendChild(subentry)
632
subentry.appendChild(dom.createTextNode(pciid))
634
subentry = dom.createElement("vendorid")
635
entry.appendChild(subentry)
636
subentry.appendChild(dom.createTextNode(vendorid))
638
subentry = dom.createElement("deviceid")
639
entry.appendChild(subentry)
640
subentry.appendChild(dom.createTextNode(deviceid))
642
if assigned.has_key(pciid):
643
vmuuid, vmnum, vendorid, deviceid, mac, vlan = assigned[pciid]
644
aentry = dom.createElement("assigned")
645
entry.appendChild(aentry)
647
subentry = dom.createElement("vm")
648
aentry.appendChild(subentry)
649
subentry.appendChild(dom.createTextNode(vmuuid))
651
subentry = dom.createElement("index")
652
aentry.appendChild(subentry)
653
subentry.appendChild(dom.createTextNode(str(vmnum)))
656
subentry = dom.createElement("mac")
657
aentry.appendChild(subentry)
658
subentry.appendChild(dom.createTextNode(mac))
660
subentry = dom.createElement("vlan")
661
aentry.appendChild(subentry)
662
subentry.appendChild(dom.createTextNode(vlan))
664
return dom.toprettyxml()
666
def get_vm(session, args):
667
"""Return a description of the SR-IOV config for the specified VM."""
668
if not args.has_key("uuid"):
669
raise "No VM UUID specified, please use the 'uuid' argument"
670
vmuuid = args["uuid"]
672
current = _get_vm_assignments(session, vmuuid)
673
indexlist = current.keys()
675
dom = xml.dom.minidom.Document()
676
element = dom.createElement("iovirt")
677
dom.appendChild(element)
678
vmentry = dom.createElement("vm")
679
element.appendChild(vmentry)
680
subentry = dom.createElement("uuid")
681
vmentry.appendChild(subentry)
682
subentry.appendChild(dom.createTextNode(vmuuid))
684
entry = dom.createElement("passthrough")
685
vmentry.appendChild(entry)
686
subentry = dom.createElement("index")
687
entry.appendChild(subentry)
688
subentry.appendChild(dom.createTextNode(str(i)))
690
pciid, vendorid, deviceid, mac, vlan = current[i]
692
subentry = dom.createElement("pciid")
693
entry.appendChild(subentry)
694
subentry.appendChild(dom.createTextNode(pciid))
695
subentry = dom.createElement("vendorid")
696
entry.appendChild(subentry)
697
subentry.appendChild(dom.createTextNode(vendorid))
698
subentry = dom.createElement("deviceid")
699
entry.appendChild(subentry)
700
subentry.appendChild(dom.createTextNode(deviceid))
702
subentry = dom.createElement("mac")
703
entry.appendChild(subentry)
704
subentry.appendChild(dom.createTextNode(mac))
706
subentry = dom.createElement("vlan")
707
entry.appendChild(subentry)
708
subentry.appendChild(dom.createTextNode(vlan))
710
vfnum, ethdev = vfs[pciid]
711
subentry = dom.createElement("vfnum")
712
entry.appendChild(subentry)
713
subentry.appendChild(dom.createTextNode(vfnum))
714
subentry = dom.createElement("device")
715
entry.appendChild(subentry)
716
subentry.appendChild(dom.createTextNode(ethdev))
717
subentry = dom.createElement("pttype")
718
entry.appendChild(subentry)
719
subentry.appendChild(dom.createTextNode("vf"))
721
subentry = dom.createElement("pttype")
722
entry.appendChild(subentry)
723
subentry.appendChild(dom.createTextNode("pcidevice"))
724
return dom.toprettyxml()
726
def prep_for_vm(session, args):
727
if not args.has_key("uuid"):
728
raise "No VM UUID specified, please use the 'uuid' argument"
729
vmuuid = args["uuid"]
730
current = _get_vm_assignments(session, vmuuid)
733
for i in current.keys():
734
pciid, vendorid, deviceid, mac, vlan = current[i]
735
if not pciid in vfs.keys():
736
# This is probably a non SR-IOV PCI device being passed
737
# through. Log that we cannot find details and carry on
738
# processing the device list.
739
syslog.syslog("Could not find VF details for %s for %s, assume it is a non SR-IOV passthrough" % (pciid, vmuuid))
741
vfnum, ethdev = vfs[pciid]
743
# Check MAC really is a MAC
744
if not re.match("^([0-9a-fA-F:]+)$", mac):
745
raise "Unexpected MAC text '%s' for VM %s" % (mac, vmuuid)
746
cmd = "%s link set %s vf %s mac %s" % (ipcmd, ethdev, vfnum, mac)
748
syslog.syslog("Setting VF MAC with '%s' for VM %s" % (cmd, vmuuid))
751
# No VLAN may need explicit clearly of previously assigned VLAN
753
# Check VLAN really is an integer
754
if not re.match("^\d+$", vlan):
755
raise "Unexpected VLAN text '%s' for VM %s" % (vlan, vmuuid)
756
cmd2 = "%s link set %s vf %s vlan %s" % (ipcmd, ethdev, vfnum, vlan)
758
syslog.syslog("Setting VF VLAN with '%s' for VM %s" % (cmd, vmuuid))
760
return "\n".join(reply)
762
def unassign_all(session, args):
763
"""Clear all SR-IOV and PCI passthrough devices from a VM."""
764
if not args.has_key("uuid"):
765
raise "No VM UUID specified, please use the 'uuid' argument"
766
vmuuid = args["uuid"]
769
_set_vm_assignments(session, vmuuid, {})
772
def change_vf_mac(session, args):
773
"""Change the MAC address for a VF already assigned to a VM."""
775
if not args.has_key("mac"):
776
raise "Need to specify a new MAC address"
779
if not args.has_key("uuid"):
780
raise "No VM UUID specified, please use the 'uuid' argument"
781
vmuuid = args["uuid"]
783
# Specify the VF by index
784
if not args.has_key("index"):
785
raise "Need to specify the VF index"
786
index = int(args["index"])
788
# Current assignments
789
current = _get_vm_assignments(session, vmuuid)
792
if not current.has_key(index):
793
raise "VF index %u not found for VM %s" % (index, vmuuid)
795
current[index] = (c[0], c[1], c[2], mac, c[4])
798
_set_vm_assignments(session, vmuuid, current)
802
def change_vf_vlan(session, args):
803
"""Change the VLAN for a VF already assigned to a VM.
804
Use vlan=None to remove VLAN tagging."""
806
if not args.has_key("vlan"):
807
raise "Need to specify a new VLAN"
809
if vlan.lower() == "none":
812
if not args.has_key("uuid"):
813
raise "No VM UUID specified, please use the 'uuid' argument"
814
vmuuid = args["uuid"]
816
# Specify the VF by index
817
if not args.has_key("index"):
818
raise "Need to specify the VF index"
819
index = int(args["index"])
821
# Current assignments
822
current = _get_vm_assignments(session, vmuuid)
825
if not current.has_key(index):
826
raise "VF index %u not found for VM %s" % (index, vmuuid)
828
current[index] = (c[0], c[1], c[2], c[3], vlan)
831
_set_vm_assignments(session, vmuuid, current)
835
if __name__ == "__main__":
836
XenAPIPlugin.dispatch({"enable_iommu": enable_iommu,
837
"assign_free_vf": assign_free_vf,
838
"show_summary": show_summary,
839
"unassign_vf": unassign_vf,
840
"assign_free_pci_device": assign_free_pci_device,
841
"unassign_pci_device": unassign_pci_device,
843
"prep_for_vm": prep_for_vm,
844
"list_pci_devices": list_pci_devices,
845
"unassign_all": unassign_all,
846
"change_vf_vlan": change_vf_vlan,
847
"change_vf_mac": change_vf_mac})