Revision 2435f63b lib/hypervisor/hv_kvm.py

b/lib/hypervisor/hv_kvm.py
38 38
import stat
39 39
import StringIO
40 40
import fdsend
41
from bitarray import bitarray
41 42
try:
42 43
  import affinity   # pylint: disable=F0401
43 44
except ImportError:
......
68 69
IFF_NO_PI = 0x1000
69 70
IFF_VNET_HDR = 0x4000
70 71

  
72
FREE = bitarray("0")
71 73

  
72 74
def _ProbeTapVnetHdr(fd):
73 75
  """Check whether to enable the IFF_VNET_HDR flag.
......
512 514
  _CPU_INFO_CMD = "info cpus"
513 515
  _CONT_CMD = "cont"
514 516

  
517
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
518
  _INFO_PCI_CMD = "info pci"
519

  
520

  
515 521
  ANCILLARY_FILES = [
516 522
    _KVM_NETWORK_SCRIPT,
517 523
    ]
......
990 996
          boot_val = ",boot=on"
991 997
      drive_val = "file=%s,format=raw%s%s" % \
992 998
                  (dev_path, boot_val, cache_val)
993
      if cfdev.pci:
999
      if cfdev.idx is not None:
994 1000
        #TODO: name id after model
995
        drive_val += (",bus=0,unit=%d,if=none,id=drive%d" %
996
                      (cfdev.pci, cfdev.idx))
1001
        drive_val += (",if=none,id=drive%d" % cfdev.idx)
1002
        if cfdev.pci is not None:
1003
          drive_val += (",bus=0,unit=%d" % cfdev.pci)
997 1004
      else:
998 1005
        drive_val += if_val
999 1006

  
1000 1007
      kvm_cmd.extend(["-drive", drive_val])
1001 1008

  
1002
      if cfdev.pci:
1003
        dev_val = ("%s,bus=pci.0,addr=%s,drive=drive%d,id=virtio-blk-pci.%d" %
1004
                   (disk_model, hex(cfdev.pci), cfdev.idx, cfdev.idx))
1009
      if cfdev.idx is not None:
1010
        dev_val = ("%s,drive=drive%d,id=virtio-blk-pci.%d" %
1011
                    (disk_model, cfdev.idx, cfdev.idx))
1012
        if cfdev.pci is not None:
1013
          dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1005 1014
        kvm_cmd.extend(["-device", dev_val])
1006 1015

  
1007 1016
    return kvm_cmd
......
1465 1474
        tapfds.append(tapfd)
1466 1475
        taps.append(tapname)
1467 1476
        if (v_major, v_min) >= (0, 12):
1468
          if nic.pci:
1469
            nic_idx = nic.idx
1477
          nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1478
          if nic.idx:
1479
            nic_val += (",netdev=netdev%d,id=virtio-net-pci.%d" %
1480
                        (nic.idx, nic.idx))
1481
            if nic.pci is not None:
1482
              nic_val += (",bus=pci.0,addr=%s" % hex(nic.pci))
1470 1483
          else:
1471
            nic_idx = nic_seq
1472
          nic_val = ("%s,mac=%s,netdev=netdev%d" %
1473
                     (nic_model, nic.mac, nic_idx))
1474
          if nic.pci:
1475
            nic_val += (",bus=pci.0,addr=%s,id=virtio-net-pci.%d" %
1476
                        (hex(nic.pci), nic_idx))
1477
          tap_val = "type=tap,id=netdev%d,fd=%d%s" % (nic_idx, tapfd, tap_extra)
1484
            nic_val += (",netdev=netdev%d,id=virtio-net-pci.%d" %
1485
                        (nic_seq, nic_seq))
1486
          tap_val = ("type=tap,id=netdev%d,fd=%d%s" %
1487
                     (nic.idx or nic_seq, tapfd, tap_extra))
1478 1488
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1479 1489
        else:
1480 1490
          nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
......
1625 1635

  
1626 1636
    return result
1627 1637

  
1638
  def _FindFreePCISlot(self, instance_name):
1639
    slots = bitarray(32)
1640
    slots.setall(False)
1641
    output = self._CallMonitorCommand(instance_name, self._INFO_PCI_CMD)
1642
    for line in output.stdout.splitlines():
1643
      match = self._INFO_PCI_RE.search(line)
1644
      if match:
1645
        slot = int(match.group(1))
1646
        slots[slot] = True
1647

  
1648
    free = slots.search(FREE, 1)
1649
    if not free:
1650
      raise errors.HypervisorError("All PCI slots occupied")
1651

  
1652
    return int(free[0])
1653

  
1654
  def _HotplugEnabled(self, instance_name):
1655
    if not self._InstancePidAlive(instance_name)[2]:
1656
      logging.info("Cannot hotplug. Instance %s not alive", instance_name)
1657
      return False
1658

  
1659
    _, v_major, v_min, _ = self._GetKVMVersion()
1660
    return (v_major, v_min) >= (1, 0)
1661

  
1628 1662
  def HotAddDisk(self, instance, disk, dev_path, _):
1629 1663
    """Hotadd new disk to the VM
1630 1664

  
1631 1665
    """
1632
    if not self._InstancePidAlive(instance.name)[2]:
1633
      logging.info("Cannot hotplug. Instance %s not alive", instance.name)
1634
      return disk.ToDict()
1635

  
1636
    _, v_major, v_min, _ = self._GetKVMVersion()
1637
    if (v_major, v_min) >= (1, 0) and disk.pci:
1666
    if self._HotplugEnabled(instance.name):
1667
      disk.pci = self._FindFreePCISlot(instance.name)
1638 1668
      idx = disk.idx
1639 1669
      command = ("drive_add dummy file=%s,if=none,id=drive%d,format=raw" %
1640 1670
                 (dev_path, idx))
......
1656 1686
      new_kvm_runtime = (kvm_cmd, kvm_nics, hvparams, block_devices)
1657 1687
      self._SaveKVMRuntime(instance, new_kvm_runtime)
1658 1688

  
1659
    return disk.ToDict()
1689
    return disk.pci
1660 1690

  
1661 1691
  def HotDelDisk(self, instance, disk, _):
1662 1692
    """Hotdel disk to the VM
1663 1693

  
1664 1694
    """
1665
    if not self._InstancePidAlive(instance.name)[2]:
1666
      logging.info("Cannot hotplug. Instance %s not alive", instance.name)
1667
      return disk.ToDict()
1668

  
1669
    _, v_major, v_min, _ = self._GetKVMVersion()
1670
    if (v_major, v_min) >= (1, 0) and disk.pci:
1695
    if self._HotplugEnabled(instance.name):
1671 1696
      idx = disk.idx
1672 1697

  
1673 1698
      command = "device_del virtio-blk-pci.%d" % idx
......
1693 1718
      new_kvm_runtime = (kvm_cmd, kvm_nics, hvparams, block_devices)
1694 1719
      self._SaveKVMRuntime(instance, new_kvm_runtime)
1695 1720

  
1696
    return disk.ToDict()
1697

  
1698 1721
  def HotAddNic(self, instance, nic, seq):
1699 1722
    """Hotadd new nic to the VM
1700 1723

  
1701 1724
    """
1702
    if not self._InstancePidAlive(instance.name)[2]:
1703
      logging.info("Cannot hotplug. Instance %s not alive", instance.name)
1704
      return nic.ToDict()
1705

  
1706
    _, v_major, v_min, _ = self._GetKVMVersion()
1707
    if (v_major, v_min) >= (1, 0) and nic.pci:
1725
    if self._HotplugEnabled(instance.name):
1726
      nic.pci = self._FindFreePCISlot(instance.name)
1708 1727
      mac = nic.mac
1709 1728
      idx = nic.idx
1710 1729

  
......
1736 1755
      new_kvm_runtime = (kvm_cmd, kvm_nics, hvparams, block_devices)
1737 1756
      self._SaveKVMRuntime(instance, new_kvm_runtime)
1738 1757

  
1739
    return nic.ToDict()
1758
    return nic.pci
1740 1759

  
1741 1760
  def HotDelNic(self, instance, nic, _):
1742 1761
    """Hotadd new nic to the VM
1743 1762

  
1744 1763
    """
1745
    if not self._InstancePidAlive(instance.name)[2]:
1746
      logging.info("Cannot hotplug. Instance %s not alive", instance.name)
1747
      return nic.ToDict()
1748

  
1749
    _, v_major, v_min, _ = self._GetKVMVersion()
1750
    if (v_major, v_min) >= (1, 0) and nic.pci:
1764
    if self._HotplugEnabled(instance.name):
1751 1765
      idx = nic.idx
1752 1766

  
1753 1767
      command = "device_del virtio-net-pci.%d" % idx
......
1772 1786
      new_kvm_runtime = (kvm_cmd, kvm_nics, hvparams, block_devices)
1773 1787
      self._SaveKVMRuntime(instance, new_kvm_runtime)
1774 1788

  
1775
    return nic.ToDict()
1776 1789

  
1777 1790
  def _PassTapFd(self, instance, fd, nic):
1778 1791
    monsock = utils.ShellQuote(self._InstanceMonitor(instance.name))

Also available in: Unified diff