package org.ovirt.engine.core.bll.hostdev; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import javax.annotation.PostConstruct; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import org.ovirt.engine.core.bll.LockMessagesMatchUtil; import org.ovirt.engine.core.bll.interfaces.BackendInternal; import org.ovirt.engine.core.bll.network.host.NetworkDeviceHelper; import org.ovirt.engine.core.common.BackendService; import org.ovirt.engine.core.common.action.VdcActionParametersBase; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.action.VdsActionParameters; import org.ovirt.engine.core.common.businessentities.HostDevice; import org.ovirt.engine.core.common.businessentities.VDSStatus; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.businessentities.VmDevice; import org.ovirt.engine.core.common.businessentities.VmDeviceGeneralType; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.locks.LockingGroup; import org.ovirt.engine.core.common.queries.IdQueryParameters; import org.ovirt.engine.core.common.queries.VdcQueryType; import org.ovirt.engine.core.common.utils.Pair; import org.ovirt.engine.core.common.utils.VmDeviceType; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dao.HostDeviceDao; import org.ovirt.engine.core.dao.VdsDynamicDao; import org.ovirt.engine.core.dao.VmDeviceDao; import org.ovirt.engine.core.utils.lock.EngineLock; import org.ovirt.engine.core.utils.lock.LockManager; @ApplicationScoped public class HostDeviceManager implements BackendService { @Inject private VdsDynamicDao hostDynamicDao; @Inject private LockManager lockManager; @Inject private HostDeviceDao hostDeviceDao; @Inject private VmDeviceDao vmDeviceDao; @Inject private BackendInternal backend; @Inject private NetworkDeviceHelper networkDeviceHelper; @PostConstruct private void init() { ArrayList<VdcActionParametersBase> parameters = new ArrayList<>(); // It is sufficient to refresh only the devices of 'UP' hosts since other hosts // will have their devices refreshed in InitVdsOnUpCommand for (Guid hostId : hostDynamicDao.getIdsOfHostsWithStatus(VDSStatus.Up)) { parameters.add(new VdsActionParameters(hostId)); } backend.runInternalMultipleActions(VdcActionType.RefreshHostDevices, parameters); hostDeviceDao.cleanDownVms(); } /** * Checks whether the specified VM is pinned to a host and has host devices directly attached to it * * @return true if the specified VM is pinned to a host and has host devices directly attached to it */ public boolean checkVmNeedsDirectPassthrough(VM vm) { return vm.getDedicatedVmForVdsList().size() > 0 && checkVmNeedsDirectPassthrough(vm.getId()); } /** * Checks whether one of host devices attached to given VM is of 'pci' capability. */ public boolean checkVmNeedsPciDevices(Guid vmId) { return hostDeviceDao .getVmExtendedHostDevicesByVmId(vmId) .stream() .anyMatch(HostDevice::isPci); } private boolean checkVmNeedsDirectPassthrough(Guid vmId) { return vmDeviceDao.existsVmDeviceByVmIdAndType(vmId, VmDeviceGeneralType.HOSTDEV); } private boolean checkVmNeedsHostDevices(Guid vmId) { List<VmDevice> vfs = vmDeviceDao.getVmDeviceByVmIdTypeAndDevice(vmId, VmDeviceGeneralType.INTERFACE, VmDeviceType.HOST_DEVICE.getName()); return !vfs.isEmpty() || checkVmNeedsDirectPassthrough(vmId); } public boolean checkVmHostDeviceAvailability(VM vm, Guid vdsId) { if (!hostDeviceDao.checkVmHostDeviceAvailability(vm.getId(), vdsId)) { return false; } List<HostDevice> devices = backend.runInternalQuery(VdcQueryType.GetExtendedVmHostDevicesByVmId, new IdQueryParameters(vm.getId())).getReturnValue(); for (HostDevice device : devices) { if (!networkDeviceHelper.isDeviceNetworkFree(device)) { return false; } } return true; } public void allocateVmHostDevices(VM vm) { hostDeviceDao.markHostDevicesUsedByVmId(vm.getId(), vm.getDedicatedVmForVdsList().get(0)); } public void freeVmHostDevices(Guid vmId) { hostDeviceDao.freeHostDevicesUsedByVmId(vmId); } public void acquireHostDevicesLock(Guid vdsId) { lockManager.acquireLockWait(new EngineLock(getExclusiveLockForHostDevices(vdsId))); } public void releaseHostDevicesLock(Guid vdsId) { lockManager.releaseLock(new EngineLock(getExclusiveLockForHostDevices(vdsId))); } private static Map<String, Pair<String, String>> getExclusiveLockForHostDevices(Guid vdsId) { return Collections.singletonMap( vdsId.toString(), LockMessagesMatchUtil.makeLockingPair( LockingGroup.HOST_DEVICES, EngineMessage.ACTION_TYPE_FAILED_OBJECT_LOCKED)); } /** * Calls <code>VdcActionType.RefreshHost</code> on the specified host, in case any of the specified vms contain * host devices (that were attached directly or via the SRIOV scheduling) */ public void refreshHostIfAnyVmHasHostDevices(Collection<Guid> vmIds, Guid hostId) { for (Guid vmId : vmIds) { if (checkVmNeedsHostDevices(vmId)) { backend.runInternalAction(VdcActionType.RefreshHost, new VdsActionParameters(hostId)); return; } } } }