This is an automated email from the ASF dual-hosted git repository. rohit pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/main by this push: new 9d46df57f2c kvm: add vm setting for nic multiqueue number and packed virtqueues (#7333) 9d46df57f2c is described below commit 9d46df57f2c124c53aee4ede97d5beea8a1076d1 Author: Wei Zhou <weiz...@apache.org> AuthorDate: Tue May 9 11:49:26 2023 +0200 kvm: add vm setting for nic multiqueue number and packed virtqueues (#7333) This PR adds two vm setting for user vms on KVM - nic multiqueue number - packed virtqueues enabled . optional are true and false (false by default). It requires qemu>=4.2.0 and libvirt >=6.3.0 Tested ok on ubuntu 22 and rocky 8.4 --- .../main/java/com/cloud/vm/VmDetailConstants.java | 4 ++ .../org/apache/cloudstack/api/ApiConstants.java | 2 + .../api/command/user/vm/DeployVMCmd.java | 16 +++++++ .../kvm/resource/LibvirtComputingResource.java | 36 +++++++++++++-- .../kvm/resource/LibvirtDomainXMLParser.java | 9 ++++ .../hypervisor/kvm/resource/LibvirtVMDef.java | 27 +++++++++++ .../wrapper/LibvirtPlugNicCommandWrapper.java | 3 ++ .../LibvirtPrepareForMigrationCommandWrapper.java | 3 ++ .../wrapper/LibvirtReplugNicCommandWrapper.java | 4 +- .../hypervisor/kvm/resource/LibvirtVMDefTest.java | 52 ++++++++++++++++++++++ scripts/vm/network/tungsten/create_tap_device.sh | 4 +- scripts/vm/network/tungsten/delete_tap_device.sh | 5 ++- .../java/com/cloud/api/query/QueryManagerImpl.java | 2 + ui/public/locales/en.json | 4 ++ ui/src/views/compute/DeployVM.vue | 21 ++++++++- 15 files changed, 184 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/com/cloud/vm/VmDetailConstants.java b/api/src/main/java/com/cloud/vm/VmDetailConstants.java index dd0a5d754bb..add2518321b 100644 --- a/api/src/main/java/com/cloud/vm/VmDetailConstants.java +++ b/api/src/main/java/com/cloud/vm/VmDetailConstants.java @@ -48,6 +48,10 @@ public interface VmDetailConstants { String IOTHREADS = "iothreads"; String IO_POLICY = "io.policy"; + // KVM specific, the number of queues for multiqueue NICs + String NIC_MULTIQUEUE_NUMBER = "nic.multiqueue.number"; + String NIC_PACKED_VIRTQUEUES_ENABLED = "nic.packed.virtqueues.enabled"; + // Mac OSX guest specific (internal) String SMC_PRESENT = "smc.present"; String FIRMWARE = "firmware"; 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 c1438251b85..76c0830527f 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -299,6 +299,8 @@ public class ApiConstants { public static final String NIC = "nic"; public static final String NIC_NETWORK_LIST = "nicnetworklist"; public static final String NIC_IP_ADDRESS_LIST = "nicipaddresslist"; + public static final String NIC_MULTIQUEUE_NUMBER = "nicmultiqueuenumber"; + public static final String NIC_PACKED_VIRTQUEUES_ENABLED = "nicpackedvirtqueuesenabled"; public static final String NEW_START_IP = "newstartip"; public static final String NEW_END_IP = "newendip"; public static final String NUM_RETRIES = "numretries"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java index 628b332cecb..17eb92854a1 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -264,6 +264,14 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG @Parameter(name = ApiConstants.IO_DRIVER_POLICY, type = CommandType.STRING, description = "Controls specific policies on IO") private String ioDriverPolicy; + @Parameter(name = ApiConstants.NIC_MULTIQUEUE_NUMBER, type = CommandType.INTEGER, since = "4.18", + description = "The number of queues for multiqueue NICs.") + private Integer nicMultiqueueNumber; + + @Parameter(name = ApiConstants.NIC_PACKED_VIRTQUEUES_ENABLED, type = CommandType.BOOLEAN, since = "4.18", + description = "Enable packed virtqueues or not.") + private Boolean nicPackedVirtQueues; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -338,6 +346,14 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG customparameterMap.put(VmDetailConstants.IOTHREADS, BooleanUtils.toStringTrueFalse(iothreadsEnabled)); } + if (nicMultiqueueNumber != null) { + customparameterMap.put(VmDetailConstants.NIC_MULTIQUEUE_NUMBER, nicMultiqueueNumber.toString()); + } + + if (BooleanUtils.toBoolean(nicPackedVirtQueues)) { + customparameterMap.put(VmDetailConstants.NIC_PACKED_VIRTQUEUES_ENABLED, BooleanUtils.toStringTrueFalse(nicPackedVirtQueues)); + } + return customparameterMap; } 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 2ac6da86dc6..f4ce29c5762 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 @@ -2843,7 +2843,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv for (int i = 0; i < nics.length; i++) { for (final NicTO nic : vmSpec.getNics()) { if (nic.getDeviceId() == i) { - createVif(vm, nic, nicAdapter, extraConfig); + createVif(vm, vmSpec, nic, nicAdapter, extraConfig); } } } @@ -3224,12 +3224,16 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } } - private void createVif(final LibvirtVMDef vm, final NicTO nic, final String nicAdapter, Map<String, String> extraConfig) throws InternalErrorException, LibvirtException { + private void createVif(final LibvirtVMDef vm, final VirtualMachineTO vmSpec, final NicTO nic, final String nicAdapter, Map<String, String> extraConfig) throws InternalErrorException, LibvirtException { if (vm.getDevices() == null) { s_logger.error("LibvirtVMDef object get devices with null result"); throw new InternalErrorException("LibvirtVMDef object get devices with null result"); } - vm.getDevices().addDevice(getVifDriver(nic.getType(), nic.getName()).plug(nic, vm.getPlatformEmulator(), nicAdapter, extraConfig)); + final InterfaceDef interfaceDef = getVifDriver(nic.getType(), nic.getName()).plug(nic, vm.getPlatformEmulator(), nicAdapter, extraConfig); + if (vmSpec.getDetails() != null) { + setInterfaceDefQueueSettings(vmSpec.getDetails(), vmSpec.getCpus(), interfaceDef); + } + vm.getDevices().addDevice(interfaceDef); } public boolean cleanupDisk(Map<String, String> volumeToDisconnect) { @@ -5143,4 +5147,30 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv public static String generateSecretUUIDFromString(String seed) { return UUID.nameUUIDFromBytes(seed.getBytes()).toString(); } + + public void setInterfaceDefQueueSettings(Map<String, String> details, Integer cpus, InterfaceDef interfaceDef) { + String nicMultiqueueNumber = details.get(VmDetailConstants.NIC_MULTIQUEUE_NUMBER); + if (nicMultiqueueNumber != null) { + try { + Integer nicMultiqueueNumberInteger = Integer.valueOf(nicMultiqueueNumber); + if (nicMultiqueueNumberInteger == InterfaceDef.MULTI_QUEUE_NUMBER_MEANS_CPU_CORES) { + if (cpus != null) { + interfaceDef.setMultiQueueNumber(cpus); + } + } else { + interfaceDef.setMultiQueueNumber(nicMultiqueueNumberInteger); + } + } catch (NumberFormatException ex) { + s_logger.warn(String.format("VM details %s is not a valid integer value %s", VmDetailConstants.NIC_MULTIQUEUE_NUMBER, nicMultiqueueNumber)); + } + } + String nicPackedEnabled = details.get(VmDetailConstants.NIC_PACKED_VIRTQUEUES_ENABLED); + if (nicPackedEnabled != null) { + try { + interfaceDef.setPackedVirtQueues(Boolean.valueOf(nicPackedEnabled)); + } catch (NumberFormatException ex) { + s_logger.warn(String.format("VM details %s is not a valid Boolean value %s", VmDetailConstants.NIC_PACKED_VIRTQUEUES_ENABLED, nicPackedEnabled)); + } + } + } } 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 cb650e24b2f..9a27e5e4322 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 @@ -249,6 +249,15 @@ public class LibvirtDomainXMLParser { def.setDpdkOvsPath(ovsPath); def.setInterfaceMode(mode); } + String multiQueueNumber = getAttrValue("driver", "queues", nic); + if (StringUtils.isNotBlank(multiQueueNumber)) { + def.setMultiQueueNumber(Integer.valueOf(multiQueueNumber)); + } + + String packedOn = getAttrValue("driver", "packed", nic); + if (StringUtils.isNotBlank(packedOn)) { + def.setPackedVirtQueues("on".equalsIgnoreCase(packedOn)); + } if (StringUtils.isNotBlank(slot)) { def.setSlot(Integer.parseInt(slot, 16)); 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 b739c0ee0ab..aac44fc1419 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 @@ -1280,6 +1280,8 @@ public class LibvirtVMDef { DIRECT_ATTACHED_WITHOUT_DHCP, DIRECT_ATTACHED_WITH_DHCP, VNET, VLAN; } + public static final int MULTI_QUEUE_NUMBER_MEANS_CPU_CORES = -1; + private GuestNetType _netType; /* * bridge, ethernet, network, user, * internal, vhostuser @@ -1305,6 +1307,8 @@ public class LibvirtVMDef { private String _interfaceMode; private String _userIp4Network; private Integer _userIp4Prefix; + private Integer _multiQueueNumber; + private Boolean _packedVirtQueues; public void defBridgeNet(String brName, String targetBrName, String macAddr, NicModel model) { defBridgeNet(brName, targetBrName, macAddr, model, 0); @@ -1493,6 +1497,14 @@ public class LibvirtVMDef { _interfaceMode = mode; } + public void setMultiQueueNumber(Integer multiQueueNumber) { + this._multiQueueNumber = multiQueueNumber; + } + + public void setPackedVirtQueues(Boolean packedVirtQueues) { + this._packedVirtQueues = packedVirtQueues; + } + public String getContent() { StringBuilder netBuilder = new StringBuilder(); if (_netType == GuestNetType.BRIDGE) { @@ -1515,6 +1527,21 @@ public class LibvirtVMDef { if (_model != null) { netBuilder.append("<model type='" + _model + "'/>\n"); } + if (NicModel.VIRTIO.equals(_model)) { + boolean isMultiQueueNumberSpecified = _multiQueueNumber != null; + boolean isPackedVirtQueuesEnabled = _packedVirtQueues != null && _packedVirtQueues + && s_qemuVersion >= 4200000 && s_libvirtVersion >= 6300000; + if (isMultiQueueNumberSpecified || isPackedVirtQueuesEnabled) { + netBuilder.append("<driver"); + if (isMultiQueueNumberSpecified) { + netBuilder.append(" queues='" + _multiQueueNumber + "'"); + } + if (isPackedVirtQueuesEnabled) { + netBuilder.append(" packed='on'"); + } + netBuilder.append("/>\n"); + } + } if ((s_libvirtVersion >= 9004) && (_networkRateKBps > 0)) { // supported from libvirt 0.9.4 netBuilder.append("<bandwidth>\n"); netBuilder.append("<inbound average='" + _networkRateKBps + "' peak='" + _networkRateKBps + "'/>\n"); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java index ca78c718886..dffa8360c20 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java @@ -64,6 +64,9 @@ public final class LibvirtPlugNicCommandWrapper extends CommandWrapper<PlugNicCo } final VifDriver vifDriver = libvirtComputingResource.getVifDriver(nic.getType(), nic.getName()); final InterfaceDef interfaceDef = vifDriver.plug(nic, "Other PV", "", null); + if (command.getDetails() != null) { + libvirtComputingResource.setInterfaceDefQueueSettings(command.getDetails(), null, interfaceDef); + } vm.attachDevice(interfaceDef.toString()); // apply default network rules on new nic 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 9109d579c5b..ec9e67e894c 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 @@ -80,6 +80,9 @@ public final class LibvirtPrepareForMigrationCommandWrapper extends CommandWrapp for (final NicTO nic : nics) { LibvirtVMDef.InterfaceDef interfaceDef = libvirtComputingResource.getVifDriver(nic.getType(), nic.getName()).plug(nic, null, "", vm.getExtraConfig()); + if (vm.getDetails() != null) { + libvirtComputingResource.setInterfaceDefQueueSettings(vm.getDetails(), vm.getCpus(), interfaceDef); + } if (interfaceDef != null && interfaceDef.getNetType() == GuestNetType.VHOSTUSER) { DpdkTO to = new DpdkTO(interfaceDef.getDpdkOvsPath(), interfaceDef.getDpdkSourcePort(), interfaceDef.getInterfaceMode()); dpdkInterfaceMapping.put(nic.getMac(), to); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapper.java index ff9ae6d0eb6..558c7f0441c 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapper.java @@ -66,7 +66,9 @@ public final class LibvirtReplugNicCommandWrapper extends CommandWrapper<ReplugN final VifDriver newVifDriver = libvirtComputingResource.getVifDriver(nic.getType(), nic.getName()); final InterfaceDef interfaceDef = newVifDriver.plug(nic, "Other PV", oldPluggedNic.getModel().toString(), null); - + if (command.getDetails() != null) { + libvirtComputingResource.setInterfaceDefQueueSettings(command.getDetails(), null, interfaceDef); + } interfaceDef.setSlot(oldPluggedNic.getSlot()); interfaceDef.setDevName(oldPluggedNic.getDevName()); interfaceDef.setLinkStateUp(false); diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java index ec59265c832..57bdf81f528 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java @@ -150,6 +150,58 @@ public class LibvirtVMDefTest extends TestCase { assertEquals(expected, ifDef.toString()); } + @Test + public void testInterfaceWithMultiQueueAndPacked() { + LibvirtVMDef.InterfaceDef ifDef = new LibvirtVMDef.InterfaceDef(); + ifDef.defBridgeNet("targetDeviceName", null, "00:11:22:aa:bb:dd", LibvirtVMDef.InterfaceDef.NicModel.VIRTIO); + ifDef.setMultiQueueNumber(6); + + LibvirtVMDef.setGlobalQemuVersion(5000000L); + LibvirtVMDef.setGlobalLibvirtVersion(6400000L); + + String expected = + "<interface type='" + LibvirtVMDef.InterfaceDef.GuestNetType.BRIDGE + "'>\n" + + "<source bridge='targetDeviceName'/>\n" + + "<mac address='00:11:22:aa:bb:dd'/>\n" + + "<model type='virtio'/>\n" + + "<driver queues='6'/>\n" + + "<link state='up'/>\n" + + "</interface>\n"; + assertEquals(expected, ifDef.toString()); + + ifDef.setPackedVirtQueues(true); + expected = + "<interface type='" + LibvirtVMDef.InterfaceDef.GuestNetType.BRIDGE + "'>\n" + + "<source bridge='targetDeviceName'/>\n" + + "<mac address='00:11:22:aa:bb:dd'/>\n" + + "<model type='virtio'/>\n" + + "<driver queues='6' packed='on'/>\n" + + "<link state='up'/>\n" + + "</interface>\n"; + assertEquals(expected, ifDef.toString()); + + ifDef.setMultiQueueNumber(null); + expected = + "<interface type='" + LibvirtVMDef.InterfaceDef.GuestNetType.BRIDGE + "'>\n" + + "<source bridge='targetDeviceName'/>\n" + + "<mac address='00:11:22:aa:bb:dd'/>\n" + + "<model type='virtio'/>\n" + + "<driver packed='on'/>\n" + + "<link state='up'/>\n" + + "</interface>\n"; + assertEquals(expected, ifDef.toString()); + + LibvirtVMDef.setGlobalLibvirtVersion(300000L); + expected = + "<interface type='" + LibvirtVMDef.InterfaceDef.GuestNetType.BRIDGE + "'>\n" + + "<source bridge='targetDeviceName'/>\n" + + "<mac address='00:11:22:aa:bb:dd'/>\n" + + "<model type='virtio'/>\n" + + "<link state='up'/>\n" + + "</interface>\n"; + assertEquals(expected, ifDef.toString()); + } + @Test public void testCpuModeDef() { LibvirtVMDef.CpuModeDef cpuModeDef = new LibvirtVMDef.CpuModeDef(); diff --git a/scripts/vm/network/tungsten/create_tap_device.sh b/scripts/vm/network/tungsten/create_tap_device.sh index c10a0e72105..90c24d62b3a 100755 --- a/scripts/vm/network/tungsten/create_tap_device.sh +++ b/scripts/vm/network/tungsten/create_tap_device.sh @@ -16,5 +16,5 @@ # specific language governing permissions and limitations # under the License. -ip tuntap add dev $1 mode tap -ip link set $1 up \ No newline at end of file +#ip tuntap add dev $1 mode tap multi_queue +#ip link set $1 up diff --git a/scripts/vm/network/tungsten/delete_tap_device.sh b/scripts/vm/network/tungsten/delete_tap_device.sh index 37d668af8af..8a3677236e2 100755 --- a/scripts/vm/network/tungsten/delete_tap_device.sh +++ b/scripts/vm/network/tungsten/delete_tap_device.sh @@ -16,4 +16,7 @@ # specific language governing permissions and limitations # under the License. -ip tuntap del dev $1 mode tap \ No newline at end of file +ip tuntap del dev $1 mode tap multi_queue 2>/dev/null +if [ $? -ne 0 ];then + ip tuntap del dev $1 mode tap +fi diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java index ce5b9db574d..e78f6958e1a 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -4053,6 +4053,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q options.put(VmDetailConstants.VIDEO_RAM, Collections.emptyList()); options.put(VmDetailConstants.IO_POLICY, Arrays.asList("threads", "native", "io_uring", "storage_specific")); options.put(VmDetailConstants.IOTHREADS, Arrays.asList("enabled")); + options.put(VmDetailConstants.NIC_MULTIQUEUE_NUMBER, Collections.emptyList()); + options.put(VmDetailConstants.NIC_PACKED_VIRTQUEUES_ENABLED, Arrays.asList("true", "false")); } if (HypervisorType.VMware.equals(hypervisorType)) { diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 5284a3b1379..cedb3cc930e 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -1337,6 +1337,10 @@ "label.nfsserver": "NFS server", "label.nic": "NIC", "label.nicadaptertype": "NIC adapter type", +"label.nicmultiqueuenumber" : "NIC multiqueue number", +"label.nicmultiqueuenumber.tooltip" : "NIC multiqueue number. This supports only KVM. The value \"-1\" indicates the NIC multiqueue number will be set to the vCPU number of the instance.", +"label.nicpackedvirtqueuesenabled" : "NIC packed virtqueues enabled", +"label.nicpackedvirtqueuesenabled.tooltip" : "Enable NIC packed virtqueues or not. This supports only KVM with QEMU >= 4.2.0 and Libvirt >=6.3.0.", "label.nics": "NICs", "label.no": "No", "label.no.data": "No data to show", diff --git a/ui/src/views/compute/DeployVM.vue b/ui/src/views/compute/DeployVM.vue index 064dac21e79..d635d3f8e8c 100644 --- a/ui/src/views/compute/DeployVM.vue +++ b/ui/src/views/compute/DeployVM.vue @@ -697,6 +697,23 @@ @select-affinity-group-item="($event) => updateAffinityGroups($event)" @handle-search-filter="($event) => handleSearchFilter('affinityGroups', $event)"/> </a-form-item> + <a-form-item name="nicmultiqueuenumber" ref="nicmultiqueuenumber" v-if="vm.templateid && ['KVM'].includes(hypervisor)"> + <template #label> + <tooltip-label :title="$t('label.nicmultiqueuenumber')" :tooltip="$t('label.nicmultiqueuenumber.tooltip')"/> + </template> + <a-input-number + style="width: 100%;" + v-model:value="form.nicmultiqueuenumber" /> + </a-form-item> + <a-form-item name="nicpackedvirtqueuesenabled" ref="nicpackedvirtqueuesenabled" v-if="vm.templateid && ['KVM'].includes(hypervisor)"> + <template #label> + <tooltip-label :title="$t('label.nicpackedvirtqueuesenabled')" :tooltip="$t('label.nicpackedvirtqueuesenabled.tooltip')"/> + </template> + <a-switch + v-model:checked="form.nicpackedvirtqueuesenabled" + :checked="nicpackedvirtqueuesenabled" + @change="val => { nicpackedvirtqueuesenabled = val }"/> + </a-form-item> <a-form-item name="iothreadsenabled" ref="iothreadsenabled" v-if="vm.templateid && ['KVM'].includes(hypervisor)"> <template #label> <tooltip-label :title="$t('label.iothreadsenabled')" :tooltip="$t('label.iothreadsenabled.tooltip')"/> @@ -1679,7 +1696,7 @@ export default { this.fetchInstaceGroups() this.fetchIoPolicyTypes() nextTick().then(() => { - ['name', 'keyboard', 'boottype', 'bootmode', 'userdata', 'iothreadsenabled', 'iodriverpolicy'].forEach(this.fillValue) + ['name', 'keyboard', 'boottype', 'bootmode', 'userdata', 'iothreadsenabled', 'iodriverpolicy', 'nicmultiqueuenumber', 'nicpackedvirtqueues'].forEach(this.fillValue) this.form.boottype = this.defaultBootType ? this.defaultBootType : this.options.bootTypes && this.options.bootTypes.length > 0 ? this.options.bootTypes[0].id : undefined this.form.bootmode = this.defaultBootMode ? this.defaultBootMode : this.options.bootModes && this.options.bootModes.length > 0 ? this.options.bootModes[0].id : undefined this.instanceConfig = toRaw(this.form) @@ -1977,6 +1994,8 @@ export default { deployVmData.dynamicscalingenabled = values.dynamicscalingenabled deployVmData.iothreadsenabled = values.iothreadsenabled deployVmData.iodriverpolicy = values.iodriverpolicy + deployVmData.nicmultiqueuenumber = values.nicmultiqueuenumber + deployVmData.nicpackedvirtqueuesenabled = values.nicpackedvirtqueuesenabled if (values.userdata && values.userdata.length > 0) { deployVmData.userdata = encodeURIComponent(btoa(sanitizeReverse(values.userdata))) }