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 <[email protected]>
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)))
}