diff --git a/api/src/main/java/com/cloud/agent/api/to/DpdkTO.java b/api/src/main/java/com/cloud/agent/api/to/DpdkTO.java new file mode 100644 index 00000000000..86ae27713d0 --- /dev/null +++ b/api/src/main/java/com/cloud/agent/api/to/DpdkTO.java @@ -0,0 +1,45 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.agent.api.to; + +public class DpdkTO { + + private String path; + private String port; + private String mode; + + public DpdkTO() { + } + + public DpdkTO(String path, String port, String mode) { + this.path = path; + this.port = port; + this.mode = mode; + } + + public String getPath() { + return path; + } + + public String getPort() { + return port; + } + + public String getMode() { + return mode; + } +} \ No newline at end of file diff --git a/api/src/main/java/com/cloud/agent/api/to/NicTO.java b/api/src/main/java/com/cloud/agent/api/to/NicTO.java index 48612253f93..6a77f62cb07 100644 --- a/api/src/main/java/com/cloud/agent/api/to/NicTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/NicTO.java @@ -30,7 +30,7 @@ public class NicTO extends NetworkTO { String nicUuid; List nicSecIps; Map details; - boolean dpdkDisabled; + boolean dpdkEnabled; public NicTO() { super(); @@ -111,11 +111,11 @@ public class NicTO extends NetworkTO { this.details = details; } - public boolean isDpdkDisabled() { - return dpdkDisabled; + public boolean isDpdkEnabled() { + return dpdkEnabled; } - public void setDpdkDisabled(boolean dpdkDisabled) { - this.dpdkDisabled = dpdkDisabled; + public void setDpdkEnabled(boolean dpdkEnabled) { + this.dpdkEnabled = dpdkEnabled; } } diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index c5075a3a0b5..8cb58d6b1fe 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -219,6 +219,7 @@ public class ApiConstants { public static final String OFFER_HA = "offerha"; public static final String IS_SYSTEM_OFFERING = "issystem"; public static final String IS_DEFAULT_USE = "defaultuse"; + public static final String OLD_FORMAT = "oldformat"; public static final String OP = "op"; public static final String OS_CATEGORY_ID = "oscategoryid"; public static final String OS_TYPE_ID = "ostypeid"; diff --git a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java index 80d6d4be065..740ee468702 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java @@ -435,7 +435,7 @@ public interface ResponseGenerator { UsageRecordResponse createUsageResponse(Usage usageRecord); - UsageRecordResponse createUsageResponse(Usage usageRecord, Map> resourceTagResponseMap); + UsageRecordResponse createUsageResponse(Usage usageRecord, Map> resourceTagResponseMap, boolean oldFormat); public Map> getUsageResourceTags(); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java index 2698c819c85..a5199ece944 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/usage/ListUsageRecordsCmd.java @@ -82,6 +82,9 @@ public class ListUsageRecordsCmd extends BaseListCmd { @Parameter(name = ApiConstants.INCLUDE_TAGS, type = CommandType.BOOLEAN, description = "Flag to enable display of Tags for a resource") private Boolean includeTags; + @Parameter(name = ApiConstants.OLD_FORMAT, type = CommandType.BOOLEAN, description = "Flag to enable description rendered in old format which uses internal database IDs instead of UUIDs. False by default.") + private Boolean oldFormat; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -146,6 +149,9 @@ public class ListUsageRecordsCmd extends BaseListCmd { this.usageId = usageId; } + public boolean getOldFormat() { + return oldFormat != null && oldFormat; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -168,7 +174,7 @@ public class ListUsageRecordsCmd extends BaseListCmd { resourceTagResponseMap = _responseGenerator.getUsageResourceTags(); } for (Usage usageRecord : usageRecords.first()) { - UsageRecordResponse usageResponse = _responseGenerator.createUsageResponse(usageRecord, resourceTagResponseMap); + UsageRecordResponse usageResponse = _responseGenerator.createUsageResponse(usageRecord, resourceTagResponseMap, getOldFormat()); if (usageResponse != null) { usageResponse.setObjectName("usagerecord"); usageResponses.add(usageResponse); diff --git a/api/src/main/java/org/apache/cloudstack/api/response/UsageRecordResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/UsageRecordResponse.java index c53f2b99e0b..cfc552d86b6 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/UsageRecordResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/UsageRecordResponse.java @@ -77,8 +77,8 @@ public class UsageRecordResponse extends BaseResponseWithTagInformation implemen private String virtualMachineId; @SerializedName(ApiConstants.NAME) - @Param(description = "virtual machine name") - private String vmName; + @Param(description = "resource or virtual machine name") + private String resourceName; @SerializedName("offeringid") @Param(description = "offering ID") @@ -186,8 +186,8 @@ public class UsageRecordResponse extends BaseResponseWithTagInformation implemen this.virtualMachineId = virtualMachineId; } - public void setVmName(String vmName) { - this.vmName = vmName; + public void setResourceName(String name) { + this.resourceName = name; } public void setOfferingId(String offeringId) { diff --git a/api/src/main/java/org/apache/cloudstack/usage/UsageTypes.java b/api/src/main/java/org/apache/cloudstack/usage/UsageTypes.java index f03d9a9f733..d0b700697f3 100644 --- a/api/src/main/java/org/apache/cloudstack/usage/UsageTypes.java +++ b/api/src/main/java/org/apache/cloudstack/usage/UsageTypes.java @@ -66,6 +66,7 @@ public class UsageTypes { responseList.add(new UsageTypeResponse(VM_DISK_BYTES_READ, "VM Disk usage(Bytes Read)")); responseList.add(new UsageTypeResponse(VM_DISK_BYTES_WRITE, "VM Disk usage(Bytes Write)")); responseList.add(new UsageTypeResponse(VM_SNAPSHOT, "VM Snapshot storage usage")); + responseList.add(new UsageTypeResponse(VOLUME_SECONDARY, "Volume on secondary storage usage")); responseList.add(new UsageTypeResponse(VM_SNAPSHOT_ON_PRIMARY, "VM Snapshot on primary storage usage")); return responseList; } diff --git a/core/src/main/java/com/cloud/agent/api/MigrateCommand.java b/core/src/main/java/com/cloud/agent/api/MigrateCommand.java index f189c72b5c9..93324d20730 100644 --- a/core/src/main/java/com/cloud/agent/api/MigrateCommand.java +++ b/core/src/main/java/com/cloud/agent/api/MigrateCommand.java @@ -24,6 +24,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.cloud.agent.api.to.DpdkTO; import com.cloud.agent.api.to.VirtualMachineTO; public class MigrateCommand extends Command { @@ -37,6 +38,15 @@ public class MigrateCommand extends Command { private VirtualMachineTO vmTO; private boolean executeInSequence = false; private List migrateDiskInfoList = new ArrayList<>(); + private Map dpdkInterfaceMapping = new HashMap<>(); + + public Map getDpdkInterfaceMapping() { + return dpdkInterfaceMapping; + } + + public void setDpdkInterfaceMapping(Map dpdkInterfaceMapping) { + this.dpdkInterfaceMapping = dpdkInterfaceMapping; + } protected MigrateCommand() { } diff --git a/core/src/main/java/com/cloud/agent/api/PrepareForMigrationAnswer.java b/core/src/main/java/com/cloud/agent/api/PrepareForMigrationAnswer.java index c9f23d664c9..d0a544ba081 100644 --- a/core/src/main/java/com/cloud/agent/api/PrepareForMigrationAnswer.java +++ b/core/src/main/java/com/cloud/agent/api/PrepareForMigrationAnswer.java @@ -19,7 +19,15 @@ package com.cloud.agent.api; +import com.cloud.agent.api.to.DpdkTO; + +import java.util.HashMap; +import java.util.Map; + public class PrepareForMigrationAnswer extends Answer { + + private Map dpdkInterfaceMapping = new HashMap<>(); + protected PrepareForMigrationAnswer() { } @@ -34,4 +42,12 @@ public class PrepareForMigrationAnswer extends Answer { public PrepareForMigrationAnswer(PrepareForMigrationCommand cmd) { super(cmd, true, null); } + + public void setDpdkInterfaceMapping(Map mapping) { + this.dpdkInterfaceMapping = mapping; + } + + public Map getDpdkInterfaceMapping() { + return this.dpdkInterfaceMapping; + } } diff --git a/core/src/main/java/com/cloud/agent/api/StopCommand.java b/core/src/main/java/com/cloud/agent/api/StopCommand.java index eedf736ac4c..ad6833f1fea 100644 --- a/core/src/main/java/com/cloud/agent/api/StopCommand.java +++ b/core/src/main/java/com/cloud/agent/api/StopCommand.java @@ -19,6 +19,7 @@ package com.cloud.agent.api; +import com.cloud.agent.api.to.DpdkTO; import com.cloud.agent.api.to.GPUDeviceTO; import com.cloud.vm.VirtualMachine; @@ -34,6 +35,15 @@ public class StopCommand extends RebootCommand { boolean checkBeforeCleanup = false; String controlIp = null; boolean forceStop = false; + private Map dpdkInterfaceMapping; + + public Map getDpdkInterfaceMapping() { + return dpdkInterfaceMapping; + } + + public void setDpdkInterfaceMapping(Map dpdkInterfaceMapping) { + this.dpdkInterfaceMapping = dpdkInterfaceMapping; + } /** * On KVM when using iSCSI-based managed storage, if the user shuts a VM down from the guest OS (as opposed to doing so from CloudStack), * we need to pass to the KVM agent a list of applicable iSCSI volumes that need to be disconnected. diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 354323ecd2f..79570534596 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -39,7 +39,8 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.cloudstack.api.ApiConstants; +import com.cloud.agent.api.PrepareForMigrationAnswer; +import com.cloud.agent.api.to.DpdkTO; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd; import org.apache.cloudstack.api.command.admin.volume.MigrateVolumeCmdByAdmin; @@ -1118,8 +1119,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac vmGuru.finalizeDeployment(cmds, vmProfile, dest, ctx); - addExtraConfig(vmTO); - work = _workDao.findById(work.getId()); if (work == null || work.getStep() != Step.Prepare) { throw new ConcurrentOperationException("Work steps have been changed: " + work); @@ -1284,15 +1283,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } } - private void addExtraConfig(VirtualMachineTO vmTO) { - Map details = vmTO.getDetails(); - for (String key : details.keySet()) { - if (key.startsWith(ApiConstants.EXTRA_CONFIG)) { - vmTO.addExtraConfig(key, details.get(key)); - } - } - } - // for managed storage on KVM, need to make sure the path field of the volume in question is populated with the IQN private void handlePath(final DiskTO[] disks, final HypervisorType hypervisorType) { if (hypervisorType != HypervisorType.KVM) { @@ -2362,6 +2352,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } boolean migrated = false; + Map dpdkInterfaceMapping = null; try { final boolean isWindows = _guestOsCategoryDao.findById(_guestOsDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows"); final MigrateCommand mc = new MigrateCommand(vm.getInstanceName(), dest.getHost().getPrivateIpAddress(), isWindows, to, getExecuteInSequence(vm.getHypervisorType())); @@ -2370,6 +2361,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac mc.setAutoConvergence(kvmAutoConvergence); mc.setHostGuid(dest.getHost().getGuid()); + dpdkInterfaceMapping = ((PrepareForMigrationAnswer) pfma).getDpdkInterfaceMapping(); + if (MapUtils.isNotEmpty(dpdkInterfaceMapping)) { + mc.setDpdkInterfaceMapping(dpdkInterfaceMapping); + } + try { final Answer ma = _agentMgr.send(vm.getLastHostId(), mc); if (ma == null || !ma.getResult()) { @@ -2396,7 +2392,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac if (!checkVmOnHost(vm, dstHostId)) { s_logger.error("Unable to complete migration for " + vm); try { - _agentMgr.send(srcHostId, new Commands(cleanup(vm)), null); + _agentMgr.send(srcHostId, new Commands(cleanup(vm, dpdkInterfaceMapping)), null); } catch (final AgentUnavailableException e) { s_logger.error("AgentUnavailableException while cleanup on source host: " + srcHostId); } @@ -2417,7 +2413,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac "Unable to migrate vm " + vm.getInstanceName() + " from host " + fromHost.getName() + " in zone " + dest.getDataCenter().getName() + " and pod " + dest.getPod().getName(), "Migrate Command failed. Please check logs."); try { - _agentMgr.send(dstHostId, new Commands(cleanup(vm)), null); + _agentMgr.send(dstHostId, new Commands(cleanup(vm, dpdkInterfaceMapping)), null); } catch (final AgentUnavailableException ae) { s_logger.info("Looks like the destination Host is unavailable for cleanup"); } @@ -3106,9 +3102,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } } - public Command cleanup(final VirtualMachine vm) { + public Command cleanup(final VirtualMachine vm, Map dpdkInterfaceMapping) { StopCommand cmd = new StopCommand(vm, getExecuteInSequence(vm.getHypervisorType()), false); cmd.setControlIp(getControlNicIpForVM(vm)); + if (MapUtils.isNotEmpty(dpdkInterfaceMapping)) { + cmd.setDpdkInterfaceMapping(dpdkInterfaceMapping); + } return cmd; } diff --git a/engine/schema/src/main/java/com/cloud/event/UsageEventVO.java b/engine/schema/src/main/java/com/cloud/event/UsageEventVO.java index 2278103b82e..c83bdcb8c02 100644 --- a/engine/schema/src/main/java/com/cloud/event/UsageEventVO.java +++ b/engine/schema/src/main/java/com/cloud/event/UsageEventVO.java @@ -70,7 +70,7 @@ public class UsageEventVO implements UsageEvent { private String resourceType; @Column(name = "processed") - boolean processed; + private boolean processed; @Column(name = "virtual_size") private Long virtualSize; diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41200to41300.sql b/engine/schema/src/main/resources/META-INF/db/schema-41200to41300.sql index 13a55e426c2..2bc2eac171f 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41200to41300.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41200to41300.sql @@ -19,6 +19,10 @@ -- Schema upgrade from 4.12.0.0 to 4.13.0.0 --; +-- Add support for VMware 6.7 +INSERT IGNORE INTO `cloud`.`hypervisor_capabilities` (uuid, hypervisor_type, hypervisor_version, max_guests_limit, security_group_enabled, max_data_volumes_limit, max_hosts_per_cluster, storage_motion_supported, vm_snapshot_enabled) values (UUID(), 'VMware', '6.7', 128, 0, 13, 32, 1, 1); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) SELECT UUID(),'VMware', '6.7', guest_os_name, guest_os_id, utc_timestamp(), 0 FROM `cloud`.`guest_os_hypervisor` WHERE hypervisor_type='VMware' AND hypervisor_version='6.5'; + -- DPDK client and server mode support ALTER TABLE `cloud`.`service_offering_details` CHANGE COLUMN `value` `value` TEXT NOT NULL; diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/constant/QuotaTypes.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/constant/QuotaTypes.java index 97e22da111a..2643ff33bc4 100644 --- a/framework/quota/src/main/java/org/apache/cloudstack/quota/constant/QuotaTypes.java +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/constant/QuotaTypes.java @@ -55,6 +55,7 @@ public class QuotaTypes extends UsageTypes { quotaTypeList.put(VM_DISK_BYTES_READ, new QuotaTypes(VM_DISK_BYTES_READ, "VM_DISK_BYTES_READ", "GB", "VM Disk usage(Bytes Read)")); quotaTypeList.put(VM_DISK_BYTES_WRITE, new QuotaTypes(VM_DISK_BYTES_WRITE, "VPN_USERS", "GB", "VM Disk usage(Bytes Write)")); quotaTypeList.put(VM_SNAPSHOT, new QuotaTypes(VM_SNAPSHOT, "VM_SNAPSHOT", "GB-Month", "VM Snapshot storage usage")); + quotaTypeList.put(VOLUME_SECONDARY, new QuotaTypes(VOLUME_SECONDARY, "VOLUME_SECONDARY", "GB-Month", "Volume secondary storage usage")); quotaTypeList.put(VM_SNAPSHOT_ON_PRIMARY, new QuotaTypes(VM_SNAPSHOT_ON_PRIMARY, "VM_SNAPSHOT_ON_PRIMARY", "GB-Month", "VM Snapshot primary storage usage")); quotaTypeList.put(CPU_CLOCK_RATE, new QuotaTypes(CPU_CLOCK_RATE, "CPU_CLOCK_RATE", "Compute-Month", "Quota tariff for using 1 CPU of clock rate 100MHz")); quotaTypeList.put(CPU_NUMBER, new QuotaTypes(CPU_NUMBER, "CPU_NUMBER", "Compute-Month", "Quota tariff for running VM that has 1vCPU")); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/dpdk/DPDKDriver.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/dpdk/DpdkDriver.java similarity index 88% rename from plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/dpdk/DPDKDriver.java rename to plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/dpdk/DpdkDriver.java index f5306e22353..0a010de0f04 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/dpdk/DPDKDriver.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/dpdk/DpdkDriver.java @@ -22,7 +22,7 @@ import com.cloud.utils.component.Adapter; import java.util.Map; -public interface DPDKDriver extends Adapter { +public interface DpdkDriver extends Adapter { /** * Get the next DPDK port name to be created @@ -37,17 +37,17 @@ public interface DPDKDriver extends Adapter { /** * Add OVS port (if it does not exist) to bridge with DPDK support */ - void addDpdkPort(String bridgeName, String port, String vlan, DPDKHelper.VHostUserMode vHostUserMode, String dpdkOvsPath); + void addDpdkPort(String bridgeName, String port, String vlan, DpdkHelper.VHostUserMode vHostUserMode, String dpdkOvsPath); /** * Since DPDK user client/server mode, retrieve the guest interfaces mode from the DPDK vHost User mode */ - String getGuestInterfacesModeFromDPDKVhostUserMode(DPDKHelper.VHostUserMode dpdKvHostUserMode); + String getGuestInterfacesModeFromDpdkVhostUserMode(DpdkHelper.VHostUserMode dpdKvHostUserMode); /** * Get DPDK vHost User mode from extra config. If it is not present, server is returned as default */ - DPDKHelper.VHostUserMode getDPDKvHostUserMode(Map extraConfig); + DpdkHelper.VHostUserMode getDpdkvHostUserMode(Map extraConfig); /** * Check for additional extra 'dpdk-interface' configurations, return them appended diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/dpdk/DPDKDriverImpl.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/dpdk/DpdkDriverImpl.java similarity index 81% rename from plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/dpdk/DPDKDriverImpl.java rename to plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/dpdk/DpdkDriverImpl.java index 71da0aefe40..cd962b620a7 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/dpdk/DPDKDriverImpl.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/dpdk/DpdkDriverImpl.java @@ -25,15 +25,15 @@ import org.apache.log4j.Logger; import java.util.Map; -public class DPDKDriverImpl extends AdapterBase implements DPDKDriver { +public class DpdkDriverImpl extends AdapterBase implements DpdkDriver { static final String DPDK_PORT_PREFIX = "csdpdk-"; private final String dpdkPortVhostUserType = "dpdkvhostuser"; private final String dpdkPortVhostUserClientType = "dpdkvhostuserclient"; - private static final Logger s_logger = Logger.getLogger(DPDKDriver.class); + private static final Logger s_logger = Logger.getLogger(DpdkDriver.class); - public DPDKDriverImpl() { + public DpdkDriverImpl() { } /** @@ -64,8 +64,8 @@ public class DPDKDriverImpl extends AdapterBase implements DPDKDriver { /** * Add OVS port (if it does not exist) to bridge with DPDK support */ - public void addDpdkPort(String bridgeName, String port, String vlan, DPDKHelper.VHostUserMode vHostUserMode, String dpdkOvsPath) { - String type = vHostUserMode == DPDKHelper.VHostUserMode.SERVER ? + public void addDpdkPort(String bridgeName, String port, String vlan, DpdkHelper.VHostUserMode vHostUserMode, String dpdkOvsPath) { + String type = vHostUserMode == DpdkHelper.VHostUserMode.SERVER ? dpdkPortVhostUserType : dpdkPortVhostUserClientType; @@ -74,7 +74,7 @@ public class DPDKDriverImpl extends AdapterBase implements DPDKDriver { "vlan_mode=access tag=%s " + "-- set Interface %s type=%s", bridgeName, port, vlan, port, type)); - if (vHostUserMode == DPDKHelper.VHostUserMode.CLIENT) { + if (vHostUserMode == DpdkHelper.VHostUserMode.CLIENT) { stringBuilder.append(String.format(" options:vhost-server-path=%s/%s", dpdkOvsPath, port)); } @@ -87,17 +87,17 @@ public class DPDKDriverImpl extends AdapterBase implements DPDKDriver { /** * Since DPDK user client/server mode, retrieve the guest interfaces mode from the DPDK vHost User mode */ - public String getGuestInterfacesModeFromDPDKVhostUserMode(DPDKHelper.VHostUserMode dpdKvHostUserMode) { - return dpdKvHostUserMode == DPDKHelper.VHostUserMode.CLIENT ? "server" : "client"; + public String getGuestInterfacesModeFromDpdkVhostUserMode(DpdkHelper.VHostUserMode dpdKvHostUserMode) { + return dpdKvHostUserMode == DpdkHelper.VHostUserMode.CLIENT ? "server" : "client"; } /** * Get DPDK vHost User mode from extra config. If it is not present, server is returned as default */ - public DPDKHelper.VHostUserMode getDPDKvHostUserMode(Map extraConfig) { - return extraConfig.containsKey(DPDKHelper.DPDK_VHOST_USER_MODE) ? - DPDKHelper.VHostUserMode.fromValue(extraConfig.get(DPDKHelper.DPDK_VHOST_USER_MODE)) : - DPDKHelper.VHostUserMode.SERVER; + public DpdkHelper.VHostUserMode getDpdkvHostUserMode(Map extraConfig) { + return extraConfig.containsKey(DpdkHelper.DPDK_VHOST_USER_MODE) ? + DpdkHelper.VHostUserMode.fromValue(extraConfig.get(DpdkHelper.DPDK_VHOST_USER_MODE)) : + DpdkHelper.VHostUserMode.SERVER; } /** @@ -106,7 +106,7 @@ public class DPDKDriverImpl extends AdapterBase implements DPDKDriver { public String getExtraDpdkProperties(Map extraConfig) { StringBuilder stringBuilder = new StringBuilder(); for (String key : extraConfig.keySet()) { - if (key.startsWith(DPDKHelper.DPDK_INTERFACE_PREFIX)) { + if (key.startsWith(DpdkHelper.DPDK_INTERFACE_PREFIX)) { stringBuilder.append(extraConfig.get(key)); } } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 5f2a911d6be..9319ee524d1 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -46,7 +46,7 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import com.cloud.hypervisor.kvm.dpdk.DPDKHelper; +import com.cloud.hypervisor.kvm.dpdk.DpdkHelper; import com.cloud.resource.RequestWrapper; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; @@ -2070,7 +2070,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv vm.setPlatformEmulator(vmTO.getPlatformEmulator()); Map extraConfig = vmTO.getExtraConfig(); - if (dpdkSupport && (!extraConfig.containsKey(DPDKHelper.DPDK_NUMA) || !extraConfig.containsKey(DPDKHelper.DPDK_HUGE_PAGES))) { + if (dpdkSupport && (!extraConfig.containsKey(DpdkHelper.DPDK_NUMA) || !extraConfig.containsKey(DpdkHelper.DPDK_HUGE_PAGES))) { s_logger.info("DPDK is enabled but it needs extra configurations for CPU NUMA and Huge Pages for VM deployment"); } @@ -2107,7 +2107,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv grd.setVcpuNum(vcpus); vm.addComp(grd); - if (!extraConfig.containsKey(DPDKHelper.DPDK_NUMA)) { + if (!extraConfig.containsKey(DpdkHelper.DPDK_NUMA)) { final CpuModeDef cmd = new CpuModeDef(); cmd.setMode(_guestCpuMode); cmd.setModel(_guestCpuModel); @@ -2235,7 +2235,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv if (MapUtils.isNotEmpty(extraConfig)) { StringBuilder extraConfigBuilder = new StringBuilder(); for (String key : extraConfig.keySet()) { - if (!key.startsWith(DPDKHelper.DPDK_INTERFACE_PREFIX) && !key.equals(DPDKHelper.DPDK_VHOST_USER_MODE)) { + if (!key.startsWith(DpdkHelper.DPDK_INTERFACE_PREFIX) && !key.equals(DpdkHelper.DPDK_VHOST_USER_MODE)) { extraConfigBuilder.append(extraConfig.get(key)); } } @@ -2706,7 +2706,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv final KVMHostInfo info = new KVMHostInfo(_dom0MinMem, _dom0OvercommitMem); - final String capabilities = String.join(",", info.getCapabilities()); + String capabilities = String.join(",", info.getCapabilities()); + if (dpdkSupport) { + capabilities += ",dpdk"; + } final StartupRoutingCommand cmd = new StartupRoutingCommand(info.getCpus(), info.getCpuSpeed(), info.getTotalMemory(), info.getReservedMemory(), capabilities, _hypervisorType, diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java index 97963fd2317..51ebdb3e75f 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java @@ -224,9 +224,13 @@ public class LibvirtDomainXMLParser { def.defEthernet(dev, mac, NicModel.valueOf(model.toUpperCase()), scriptPath, networkRateKBps); } else if (type.equals("vhostuser")) { String sourcePort = getAttrValue("source", "path", nic); - String[] sourcePathParts = sourcePort.split("/"); - String port = sourcePathParts[sourcePathParts.length - 1]; + String mode = getAttrValue("source", "mode", nic); + int lastSlashIndex = sourcePort.lastIndexOf("/"); + String ovsPath = sourcePort.substring(0,lastSlashIndex); + String port = sourcePort.substring(lastSlashIndex + 1); def.setDpdkSourcePort(port); + def.setDpdkOvsPath(ovsPath); + def.setInterfaceMode(mode); } if (StringUtils.isNotBlank(slot)) { diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index 400e16dba93..dab1af510bf 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -963,7 +963,7 @@ public class LibvirtVMDef { } public static class InterfaceDef { - enum GuestNetType { + public enum GuestNetType { BRIDGE("bridge"), DIRECT("direct"), NETWORK("network"), USER("user"), ETHERNET("ethernet"), INTERNAL("internal"), VHOSTUSER("vhostuser"); String _type; @@ -1176,10 +1176,24 @@ public class LibvirtVMDef { _dpdkSourcePort = port; } - @Override - public String toString() { + public String getDpdkOvsPath() { + return _dpdkSourcePath; + } + + public void setDpdkOvsPath(String path) { + _dpdkSourcePath = path; + } + + public String getInterfaceMode() { + return _interfaceMode; + } + + public void setInterfaceMode(String mode) { + _interfaceMode = mode; + } + + public String getContent() { StringBuilder netBuilder = new StringBuilder(); - netBuilder.append("\n"); if (_netType == GuestNetType.BRIDGE) { netBuilder.append("\n"); } else if (_netType == GuestNetType.NETWORK) { @@ -1233,6 +1247,14 @@ public class LibvirtVMDef { if (_slot != null) { netBuilder.append(String.format("
\n", _slot)); } + return netBuilder.toString(); + } + + @Override + public String toString() { + StringBuilder netBuilder = new StringBuilder(); + netBuilder.append("\n"); + netBuilder.append(getContent()); netBuilder.append("\n"); return netBuilder.toString(); } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java index 8208530ce22..1e7f4d5cc20 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java @@ -24,9 +24,9 @@ import java.util.Map; import javax.naming.ConfigurationException; -import com.cloud.hypervisor.kvm.dpdk.DPDKDriver; -import com.cloud.hypervisor.kvm.dpdk.DPDKDriverImpl; -import com.cloud.hypervisor.kvm.dpdk.DPDKHelper; +import com.cloud.hypervisor.kvm.dpdk.DpdkDriver; +import com.cloud.hypervisor.kvm.dpdk.DpdkDriverImpl; +import com.cloud.hypervisor.kvm.dpdk.DpdkHelper; import com.cloud.utils.exception.CloudRuntimeException; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -44,7 +44,7 @@ import com.cloud.utils.script.Script; public class OvsVifDriver extends VifDriverBase { private static final Logger s_logger = Logger.getLogger(OvsVifDriver.class); private int _timeout; - private DPDKDriver dpdkDriver; + private DpdkDriver dpdkDriver; @Override public void configure(Map params) throws ConfigurationException { @@ -59,7 +59,7 @@ public class OvsVifDriver extends VifDriverBase { String dpdk = (String) params.get("openvswitch.dpdk.enabled"); if (StringUtils.isNotBlank(dpdk) && Boolean.parseBoolean(dpdk)) { - dpdkDriver = new DPDKDriverImpl(); + dpdkDriver = new DpdkDriverImpl(); } String value = (String)params.get("scripts.timeout"); @@ -87,12 +87,34 @@ public class OvsVifDriver extends VifDriverBase { s_logger.debug("done looking for pifs, no more bridges"); } + /** + * Plug interface with DPDK support: + * - Create a new port with DPDK support for the interface + * - Set the 'intf' path to the new port + */ + protected void plugDPDKInterface(InterfaceDef intf, String trafficLabel, Map extraConfig, + String vlanId, String guestOsType, NicTO nic, String nicAdapter) { + s_logger.debug("DPDK support enabled: configuring per traffic label " + trafficLabel); + String dpdkOvsPath = _libvirtComputingResource.dpdkOvsPath; + if (StringUtils.isBlank(dpdkOvsPath)) { + throw new CloudRuntimeException("DPDK is enabled on the host but no OVS path has been provided"); + } + String port = dpdkDriver.getNextDpdkPort(); + DpdkHelper.VHostUserMode dpdKvHostUserMode = dpdkDriver.getDpdkvHostUserMode(extraConfig); + dpdkDriver.addDpdkPort(_pifs.get(trafficLabel), port, vlanId, dpdKvHostUserMode, dpdkOvsPath); + String interfaceMode = dpdkDriver.getGuestInterfacesModeFromDpdkVhostUserMode(dpdKvHostUserMode); + intf.defDpdkNet(dpdkOvsPath, port, nic.getMac(), + getGuestNicModel(guestOsType, nicAdapter), 0, + dpdkDriver.getExtraDpdkProperties(extraConfig), + interfaceMode); + } + @Override public InterfaceDef plug(NicTO nic, String guestOsType, String nicAdapter, Map extraConfig) throws InternalErrorException, LibvirtException { s_logger.debug("plugging nic=" + nic); LibvirtVMDef.InterfaceDef intf = new LibvirtVMDef.InterfaceDef(); - if (!_libvirtComputingResource.dpdkSupport || nic.isDpdkDisabled()) { + if (!_libvirtComputingResource.dpdkSupport || !nic.isDpdkEnabled()) { // Let libvirt handle OVS ports creation when DPDK property is disabled or when it is enabled but disabled for the nic // For DPDK support, libvirt does not handle ports creation, invoke 'addDpdkPort' method intf.setVirtualPortType("openvswitch"); @@ -114,20 +136,8 @@ public class OvsVifDriver extends VifDriverBase { if ((nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan || nic.getBroadcastType() == Networks.BroadcastDomainType.Pvlan) && !vlanId.equalsIgnoreCase("untagged")) { if (trafficLabel != null && !trafficLabel.isEmpty()) { - if (_libvirtComputingResource.dpdkSupport && !nic.isDpdkDisabled()) { - s_logger.debug("DPDK support enabled: configuring per traffic label " + trafficLabel); - String dpdkOvsPath = _libvirtComputingResource.dpdkOvsPath; - if (StringUtils.isBlank(dpdkOvsPath)) { - throw new CloudRuntimeException("DPDK is enabled on the host but no OVS path has been provided"); - } - String port = dpdkDriver.getNextDpdkPort(); - DPDKHelper.VHostUserMode dpdKvHostUserMode = dpdkDriver.getDPDKvHostUserMode(extraConfig); - dpdkDriver.addDpdkPort(_pifs.get(trafficLabel), port, vlanId, dpdKvHostUserMode, dpdkOvsPath); - String interfaceMode = dpdkDriver.getGuestInterfacesModeFromDPDKVhostUserMode(dpdKvHostUserMode); - intf.defDpdkNet(dpdkOvsPath, port, nic.getMac(), - getGuestNicModel(guestOsType, nicAdapter), 0, - dpdkDriver.getExtraDpdkProperties(extraConfig), - interfaceMode); + if (_libvirtComputingResource.dpdkSupport && nic.isDpdkEnabled()) { + plugDPDKInterface(intf, trafficLabel, extraConfig, vlanId, guestOsType, nic, nicAdapter); } else { s_logger.debug("creating a vlan dev and bridge for guest traffic per traffic label " + trafficLabel); intf.defBridgeNet(_pifs.get(trafficLabel), null, nic.getMac(), getGuestNicModel(guestOsType, nicAdapter), networkRateKBps); @@ -180,7 +190,7 @@ public class OvsVifDriver extends VifDriverBase { @Override public void unplug(InterfaceDef iface) { // Libvirt apparently takes care of this, see BridgeVifDriver unplug - if (_libvirtComputingResource.dpdkSupport) { + if (_libvirtComputingResource.dpdkSupport && StringUtils.isNotBlank(iface.getDpdkSourcePort())) { // If DPDK is enabled, we'll need to cleanup the port as libvirt won't String dpdkPort = iface.getDpdkSourcePort(); String cmd = String.format("ovs-vsctl del-port %s", dpdkPort); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java index 5bf8d25e949..e6d366e3b04 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java @@ -43,6 +43,7 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import com.cloud.agent.api.to.DpdkTO; import org.apache.commons.collections.MapUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; @@ -153,6 +154,11 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper dpdkPortsMapping = command.getDpdkInterfaceMapping(); + if (MapUtils.isNotEmpty(dpdkPortsMapping)) { + xmlDesc = replaceDpdkInterfaces(xmlDesc, dpdkPortsMapping); + } + dconn = libvirtUtilitiesHelper.retrieveQemuConnection(destinationUri); //run migration in thread so we can monitor it @@ -283,6 +289,76 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper dpdkPortsMapping) throws TransformerException, ParserConfigurationException, IOException, SAXException { + InputStream in = IOUtils.toInputStream(xmlDesc); + + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + Document doc = docBuilder.parse(in); + + // Get the root element + Node domainNode = doc.getFirstChild(); + + NodeList domainChildNodes = domainNode.getChildNodes(); + + for (int i = 0; i < domainChildNodes.getLength(); i++) { + Node domainChildNode = domainChildNodes.item(i); + + if ("devices".equals(domainChildNode.getNodeName())) { + NodeList devicesChildNodes = domainChildNode.getChildNodes(); + + for (int x = 0; x < devicesChildNodes.getLength(); x++) { + Node deviceChildNode = devicesChildNodes.item(x); + + if ("interface".equals(deviceChildNode.getNodeName())) { + Node interfaceNode = deviceChildNode; + NamedNodeMap attributes = interfaceNode.getAttributes(); + Node interfaceTypeAttr = attributes.getNamedItem("type"); + + if ("vhostuser".equals(interfaceTypeAttr.getNodeValue())) { + NodeList diskChildNodes = interfaceNode.getChildNodes(); + + String mac = null; + for (int y = 0; y < diskChildNodes.getLength(); y++) { + Node diskChildNode = diskChildNodes.item(y); + if (!"mac".equals(diskChildNode.getNodeName())) { + continue; + } + mac = diskChildNode.getAttributes().getNamedItem("address").getNodeValue(); + } + + if (StringUtils.isNotBlank(mac)) { + DpdkTO to = dpdkPortsMapping.get(mac); + + for (int z = 0; z < diskChildNodes.getLength(); z++) { + Node diskChildNode = diskChildNodes.item(z); + + if ("target".equals(diskChildNode.getNodeName())) { + Node targetNode = diskChildNode; + Node targetNodeAttr = targetNode.getAttributes().getNamedItem("dev"); + targetNodeAttr.setNodeValue(to.getPort()); + } else if ("source".equals(diskChildNode.getNodeName())) { + Node sourceNode = diskChildNode; + NamedNodeMap attrs = sourceNode.getAttributes(); + Node path = attrs.getNamedItem("path"); + path.setNodeValue(to.getPath() + "/" + to.getPort()); + Node mode = attrs.getNamedItem("mode"); + mode.setNodeValue(to.getMode()); + } + } + } + } + } + } + } + } + + return getXml(doc); + } + /** * In case of a local file, it deletes the file on the source host/storage pool. Otherwise (for instance iScsi) it disconnects the disk on the source storage pool.
* This method must be executed after a successful migration to a target storage pool, cleaning up the source storage. diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java index 5c9980be86d..f3f50aa61f0 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java @@ -22,20 +22,28 @@ package com.cloud.hypervisor.kvm.resource.wrapper; import com.cloud.agent.api.Answer; import com.cloud.agent.api.PrepareForMigrationAnswer; import com.cloud.agent.api.PrepareForMigrationCommand; +import com.cloud.agent.api.to.DpdkTO; import com.cloud.agent.api.to.DiskTO; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.exception.InternalErrorException; import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource; +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef; +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef.GuestNetType; import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager; import com.cloud.resource.CommandWrapper; import com.cloud.resource.ResourceWrapper; import com.cloud.storage.Volume; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.script.Script; +import org.apache.commons.collections.MapUtils; import org.apache.log4j.Logger; import org.libvirt.Connect; import org.libvirt.LibvirtException; import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; @ResourceWrapper(handles = PrepareForMigrationCommand.class) public final class LibvirtPrepareForMigrationCommandWrapper extends CommandWrapper { @@ -56,6 +64,8 @@ public final class LibvirtPrepareForMigrationCommandWrapper extends CommandWrapp final NicTO[] nics = vm.getNics(); + Map dpdkInterfaceMapping = new HashMap<>(); + boolean skipDisconnect = false; final KVMStoragePoolManager storagePoolMgr = libvirtComputingResource.getStoragePoolMgr(); @@ -63,8 +73,13 @@ public final class LibvirtPrepareForMigrationCommandWrapper extends CommandWrapp final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper(); final Connect conn = libvirtUtilitiesHelper.getConnectionByVmName(vm.getName()); + for (final NicTO nic : nics) { - libvirtComputingResource.getVifDriver(nic.getType(), nic.getName()).plug(nic, null, "", null); + LibvirtVMDef.InterfaceDef interfaceDef = libvirtComputingResource.getVifDriver(nic.getType(), nic.getName()).plug(nic, null, "", vm.getExtraConfig()); + if (interfaceDef != null && interfaceDef.getNetType() == GuestNetType.VHOSTUSER) { + DpdkTO to = new DpdkTO(interfaceDef.getDpdkOvsPath(), interfaceDef.getDpdkSourcePort(), interfaceDef.getInterfaceMode()); + dpdkInterfaceMapping.put(nic.getMac(), to); + } } /* setup disks, e.g for iso */ @@ -81,12 +96,19 @@ public final class LibvirtPrepareForMigrationCommandWrapper extends CommandWrapp return new PrepareForMigrationAnswer(command, "failed to connect physical disks to host"); } - return new PrepareForMigrationAnswer(command); - } catch (final LibvirtException e) { - return new PrepareForMigrationAnswer(command, e.toString()); - } catch (final InternalErrorException e) { - return new PrepareForMigrationAnswer(command, e.toString()); - } catch (final URISyntaxException e) { + PrepareForMigrationAnswer answer = new PrepareForMigrationAnswer(command); + if (MapUtils.isNotEmpty(dpdkInterfaceMapping)) { + answer.setDpdkInterfaceMapping(dpdkInterfaceMapping); + } + return answer; + } catch (final LibvirtException | CloudRuntimeException | InternalErrorException | URISyntaxException e) { + if (MapUtils.isNotEmpty(dpdkInterfaceMapping)) { + for (DpdkTO to : dpdkInterfaceMapping.values()) { + String cmd = String.format("ovs-vsctl del-port %s", to.getPort()); + s_logger.debug("Removing DPDK port: " + to.getPort()); + Script.runSimpleBashScript(cmd); + } + } return new PrepareForMigrationAnswer(command, e.toString()); } finally { if (!skipDisconnect) { diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java index f3839f0fc76..9c97bd4770f 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java @@ -69,7 +69,6 @@ public final class LibvirtStartCommandWrapper extends CommandWrapper dpdkInterfaceMapping = command.getDpdkInterfaceMapping(); + if (MapUtils.isNotEmpty(dpdkInterfaceMapping)) { + for (DpdkTO to : dpdkInterfaceMapping.values()) { + String portToRemove = to.getPort(); + String cmd = String.format("ovs-vsctl del-port %s", portToRemove); + s_logger.debug("Removing DPDK port: " + portToRemove); + Script.runSimpleBashScript(cmd); + } + } + } else { + for (final InterfaceDef iface : ifaces) { + // We don't know which "traffic type" is associated with + // each interface at this point, so inform all vif drivers + for (final VifDriver vifDriver : libvirtComputingResource.getAllVifDrivers()) { + vifDriver.unplug(iface); + } } } } diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/dpdk/DPDKDriverTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/dpdk/DpdkDriverTest.java similarity index 66% rename from plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/dpdk/DPDKDriverTest.java rename to plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/dpdk/DpdkDriverTest.java index a2a62fe3b7a..3bf1a6af742 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/dpdk/DPDKDriverTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/dpdk/DpdkDriverTest.java @@ -35,11 +35,11 @@ import java.util.Map; @PrepareForTest({ Script.class }) @RunWith(PowerMockRunner.class) -public class DPDKDriverTest { +public class DpdkDriverTest { private static final int dpdkPortNumber = 7; - private DPDKDriver driver = new DPDKDriverImpl(); + private DpdkDriver driver = new DpdkDriverImpl(); private Map extraConfig; @@ -59,7 +59,7 @@ public class DPDKDriverTest { @Test public void testGetDpdkLatestPortNumberUsedExistingDpdkPorts() { Mockito.when(Script.runSimpleBashScript(Matchers.anyString())). - thenReturn(DPDKDriverImpl.DPDK_PORT_PREFIX + String.valueOf(dpdkPortNumber)); + thenReturn(DpdkDriverImpl.DPDK_PORT_PREFIX + String.valueOf(dpdkPortNumber)); Assert.assertEquals(dpdkPortNumber, driver.getDpdkLatestPortNumberUsed()); } @@ -67,47 +67,47 @@ public class DPDKDriverTest { public void testGetNextDpdkPortNoDpdkPorts() { Mockito.when(Script.runSimpleBashScript(Matchers.anyString())). thenReturn(null); - String expectedPortName = DPDKDriverImpl.DPDK_PORT_PREFIX + String.valueOf(1); + String expectedPortName = DpdkDriverImpl.DPDK_PORT_PREFIX + String.valueOf(1); Assert.assertEquals(expectedPortName, driver.getNextDpdkPort()); } @Test public void testGetNextDpdkPortExistingDpdkPorts() { Mockito.when(Script.runSimpleBashScript(Matchers.anyString())). - thenReturn(DPDKDriverImpl.DPDK_PORT_PREFIX + String.valueOf(dpdkPortNumber)); - String expectedPortName = DPDKDriverImpl.DPDK_PORT_PREFIX + String.valueOf(dpdkPortNumber + 1); + thenReturn(DpdkDriverImpl.DPDK_PORT_PREFIX + String.valueOf(dpdkPortNumber)); + String expectedPortName = DpdkDriverImpl.DPDK_PORT_PREFIX + String.valueOf(dpdkPortNumber + 1); Assert.assertEquals(expectedPortName, driver.getNextDpdkPort()); } @Test - public void testGetGuestInterfacesModeFromDPDKVhostUserModeClientDPDK() { - String guestMode = driver.getGuestInterfacesModeFromDPDKVhostUserMode(DPDKHelper.VHostUserMode.CLIENT); + public void testGetGuestInterfacesModeFromDpdkVhostUserModeClientDpdk() { + String guestMode = driver.getGuestInterfacesModeFromDpdkVhostUserMode(DpdkHelper.VHostUserMode.CLIENT); Assert.assertEquals("server", guestMode); } @Test - public void testGetGuestInterfacesModeFromDPDKVhostUserModeServerDPDK() { - String guestMode = driver.getGuestInterfacesModeFromDPDKVhostUserMode(DPDKHelper.VHostUserMode.SERVER); + public void testGetGuestInterfacesModeFromDpdkVhostUserModeServerDpdk() { + String guestMode = driver.getGuestInterfacesModeFromDpdkVhostUserMode(DpdkHelper.VHostUserMode.SERVER); Assert.assertEquals("client", guestMode); } @Test - public void testGetDPDKvHostUserModeServerExtraConfig() { - extraConfig.put(DPDKHelper.DPDK_VHOST_USER_MODE, DPDKHelper.VHostUserMode.SERVER.toString()); - DPDKHelper.VHostUserMode dpdKvHostUserMode = driver.getDPDKvHostUserMode(extraConfig); - Assert.assertEquals(DPDKHelper.VHostUserMode.SERVER, dpdKvHostUserMode); + public void testGetDpdkvHostUserModeServerExtraConfig() { + extraConfig.put(DpdkHelper.DPDK_VHOST_USER_MODE, DpdkHelper.VHostUserMode.SERVER.toString()); + DpdkHelper.VHostUserMode dpdKvHostUserMode = driver.getDpdkvHostUserMode(extraConfig); + Assert.assertEquals(DpdkHelper.VHostUserMode.SERVER, dpdKvHostUserMode); } @Test - public void testGetDPDKvHostUserModeServerClientExtraConfig() { - extraConfig.put(DPDKHelper.DPDK_VHOST_USER_MODE, DPDKHelper.VHostUserMode.CLIENT.toString()); - DPDKHelper.VHostUserMode dpdKvHostUserMode = driver.getDPDKvHostUserMode(extraConfig); - Assert.assertEquals(DPDKHelper.VHostUserMode.CLIENT, dpdKvHostUserMode); + public void testGetDpdkvHostUserModeServerClientExtraConfig() { + extraConfig.put(DpdkHelper.DPDK_VHOST_USER_MODE, DpdkHelper.VHostUserMode.CLIENT.toString()); + DpdkHelper.VHostUserMode dpdKvHostUserMode = driver.getDpdkvHostUserMode(extraConfig); + Assert.assertEquals(DpdkHelper.VHostUserMode.CLIENT, dpdKvHostUserMode); } @Test - public void testGetDPDKvHostUserModeServerEmptyExtraConfig() { - DPDKHelper.VHostUserMode dpdKvHostUserMode = driver.getDPDKvHostUserMode(extraConfig); - Assert.assertEquals(DPDKHelper.VHostUserMode.SERVER, dpdKvHostUserMode); + public void testGetDpdkvHostUserModeServerEmptyExtraConfig() { + DpdkHelper.VHostUserMode dpdKvHostUserMode = driver.getDpdkvHostUserMode(extraConfig); + Assert.assertEquals(DpdkHelper.VHostUserMode.SERVER, dpdKvHostUserMode); } } \ No newline at end of file diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java index 5289481b66d..086808dbba1 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java @@ -37,6 +37,7 @@ import javax.xml.transform.TransformerException; import org.junit.Assert; import org.junit.Before; +import com.cloud.agent.api.to.DpdkTO; import org.junit.Test; import org.junit.runner.RunWith; import org.libvirt.Connect; @@ -302,6 +303,146 @@ public class LibvirtMigrateCommandWrapperTest { " \n" + ""; + private String sourceDPDKVMToMigrate = + "\n" + + " i-2-33-VM\n" + + " 14c5c052-46cb-4301-a00a-28f6cc1dc605\n" + + " Other PV (64-bit)\n" + + " 9437184\n" + + " 9437184\n" + + " \n" + + " \n" + + " \n" + + " 2\n" + + " \n" + + " 4000\n" + + " \n" + + " \n" + + " /machine\n" + + " \n" + + " \n" + + " \n" + + " Apache Software Foundation\n" + + " CloudStack KVM Hypervisor\n" + + " 14c5c052-46cb-4301-a00a-28f6cc1dc605\n" + + " \n" + + " \n" + + " \n" + + " hvm\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " destroy\n" + + " restart\n" + + " destroy\n" + + " \n" + + " /usr/libexec/qemu-kvm\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " afb1d2e401fe4694940b\n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "