From f195f2cb5844c8d16dc4db52198dcffb6cb01d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernardo=20De=20Marco=20Gon=C3=A7alves?= Date: Fri, 9 Oct 2026 14:08:37 -0300 Subject: [PATCH 1/3] Multi-queue for VRs --- .../java/com/cloud/agent/api/to/NicTO.java | 9 ++ .../java/com/cloud/network/NetworkModel.java | 4 +- .../com/cloud/network/vpc/VpcOffering.java | 4 + .../network/vpc/VpcProvisioningService.java | 3 +- .../com/cloud/offering/NetworkOffering.java | 4 + .../main/java/com/cloud/vm/NicProfile.java | 9 ++ .../apache/cloudstack/api/ApiConstants.java | 4 + .../admin/network/NetworkOfferingBaseCmd.java | 18 +++ .../admin/vpc/CreateVPCOfferingCmd.java | 16 +++ .../api/response/NetworkOfferingResponse.java | 16 +++ .../api/response/VpcOfferingResponse.java | 16 +++ .../com/cloud/agent/api/PlugNicCommand.java | 32 +++-- .../configuration/ConfigurationManager.java | 2 +- .../cloud/vm/VirtualMachineManagerImpl.java | 12 +- .../orchestration/NetworkOrchestrator.java | 130 ++++++++++++++++-- .../com/cloud/network/vpc/VpcOfferingVO.java | 20 ++- .../cloud/offerings/NetworkOfferingVO.java | 24 ++++ .../META-INF/db/schema-42300to2400.sql | 8 ++ .../db/views/cloud.network_offering_view.sql | 2 + .../db/views/cloud.vpc_offering_view.sql | 2 + .../resource/LibvirtComputingResource.java | 45 ++++-- .../wrapper/LibvirtPlugNicCommandWrapper.java | 4 +- ...virtPrepareForMigrationCommandWrapper.java | 5 +- .../LibvirtReplugNicCommandWrapper.java | 5 +- .../management/ContrailManagerImpl.java | 6 +- .../query/dao/NetworkOfferingJoinDaoImpl.java | 2 + .../api/query/dao/VpcOfferingJoinDaoImpl.java | 2 + .../api/query/vo/NetworkOfferingJoinVO.java | 16 +++ .../cloud/api/query/vo/VpcOfferingJoinVO.java | 16 +++ .../ConfigurationManagerImpl.java | 33 ++++- .../cloud/hypervisor/HypervisorGuruBase.java | 1 + .../com/cloud/network/NetworkModelImpl.java | 8 +- .../element/VpcVirtualRouterElement.java | 2 +- .../cloud/network/guru/DirectNetworkGuru.java | 2 + .../guru/ExternalGuestNetworkGuru.java | 2 + .../network/router/CommandSetupHelper.java | 4 +- .../cloud/network/router/NetworkHelper.java | 3 +- .../network/router/NetworkHelperImpl.java | 4 +- ...VpcVirtualNetworkApplianceManagerImpl.java | 33 +++-- .../network/rules/PrivateGatewayRules.java | 2 +- .../com/cloud/network/vpc/VpcManagerImpl.java | 57 ++++++-- .../ConfigurationManagerImplTest.java | 2 + .../cloud/network/MockNetworkModelImpl.java | 4 +- .../cloud/network/NetworkModelImplTest.java | 2 +- .../vpc/MockConfigurationManagerImpl.java | 2 +- .../com/cloud/vpc/MockNetworkModelImpl.java | 4 +- .../CreateNetworkOfferingTest.java | 20 +-- ui/public/locales/en.json | 3 + ui/public/locales/pt_BR.json | 3 + ui/src/config/section/offering.js | 13 +- ui/src/views/offering/AddNetworkOffering.vue | 40 +++++- ui/src/views/offering/AddVpcOffering.vue | 42 +++++- .../views/offering/CloneNetworkOffering.vue | 49 ++++++- ui/src/views/offering/CloneVpcOffering.vue | 51 ++++++- 54 files changed, 701 insertions(+), 121 deletions(-) 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 2ed7d9f9a201..6434b9da1d09 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 @@ -36,6 +36,7 @@ public class NicTO extends NetworkTO { boolean enabled; String networkSegmentName; + private Integer multiqueueNumber; public NicTO() { super(); @@ -163,4 +164,12 @@ public boolean isEnabled() { public void setEnabled(boolean enabled) { this.enabled = enabled; } + + public Integer getMultiqueueNumber() { + return multiqueueNumber; + } + + public void setMultiqueueNumber(Integer multiqueueNumber) { + this.multiqueueNumber = multiqueueNumber; + } } diff --git a/api/src/main/java/com/cloud/network/NetworkModel.java b/api/src/main/java/com/cloud/network/NetworkModel.java index 7e1a07ebeb69..148a26719fc4 100644 --- a/api/src/main/java/com/cloud/network/NetworkModel.java +++ b/api/src/main/java/com/cloud/network/NetworkModel.java @@ -321,9 +321,9 @@ public interface NetworkModel { boolean isNetworkAvailableInDomain(long networkId, long domainId); - NicProfile getNicProfile(VirtualMachine vm, long networkId, String broadcastUri); + NicProfile getNicProfile(VirtualMachine vm, long networkId, String broadcastUri, Integer multiqueueNumber); - NicProfile getNicProfile(VirtualMachine vm, Nic nic, DataCenter dataCenter); + NicProfile getNicProfile(VirtualMachine vm, Nic nic, DataCenter dataCenter, Integer multiqueueNumber); Set getAvailableIps(Network network, String requestedIp); diff --git a/api/src/main/java/com/cloud/network/vpc/VpcOffering.java b/api/src/main/java/com/cloud/network/vpc/VpcOffering.java index f84602232159..fe0b2a238f6e 100644 --- a/api/src/main/java/com/cloud/network/vpc/VpcOffering.java +++ b/api/src/main/java/com/cloud/network/vpc/VpcOffering.java @@ -86,4 +86,8 @@ public enum State { Boolean isSpecifyAsNumber(); boolean isConserveMode(); + + Integer getPublicMultiqueueNumber(); + + Integer getPrivateGatewayMultiqueueNumber(); } diff --git a/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java b/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java index 891cfb02d9df..5cf78407527d 100644 --- a/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java +++ b/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java @@ -42,7 +42,8 @@ VpcOffering createVpcOffering(String name, String displayText, List supp Map serviceCapabilitystList, NetUtils.InternetProtocol internetProtocol, Long serviceOfferingId, String externalProvider, NetworkOffering.NetworkMode networkMode, List domainIds, List zoneIds, VpcOffering.State state, - NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber, boolean conserveMode); + NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber, boolean conserveMode, + Integer publicMultiqueueNumber, Integer privateGatewayMultiqueueNumber); Pair,Integer> listVpcOfferings(ListVPCOfferingsCmd cmd); diff --git a/api/src/main/java/com/cloud/offering/NetworkOffering.java b/api/src/main/java/com/cloud/offering/NetworkOffering.java index 5000a4f8c626..d0b9e34d228c 100644 --- a/api/src/main/java/com/cloud/offering/NetworkOffering.java +++ b/api/src/main/java/com/cloud/offering/NetworkOffering.java @@ -171,4 +171,8 @@ enum RoutingMode { RoutingMode getRoutingMode(); Boolean isSpecifyAsNumber(); + + Integer getPublicMultiqueueNumber(); + + Integer getPrivateMultiqueueNumber(); } diff --git a/api/src/main/java/com/cloud/vm/NicProfile.java b/api/src/main/java/com/cloud/vm/NicProfile.java index 54a32bbcb181..58bf54caed18 100644 --- a/api/src/main/java/com/cloud/vm/NicProfile.java +++ b/api/src/main/java/com/cloud/vm/NicProfile.java @@ -55,6 +55,7 @@ public class NicProfile implements InternalIdentity, Serializable { boolean enabled; Integer orderIndex; + private Integer multiqueueNumber; // IPv4 String iPv4Address; @@ -424,6 +425,14 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } + public Integer getMultiqueueNumber() { + return multiqueueNumber; + } + + public void setMultiqueueNumber(Integer multiqueueNumber) { + this.multiqueueNumber = multiqueueNumber; + } + // // OTHER METHODS // 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 b1fc6246ff9a..aaf3c0fb7203 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -1509,6 +1509,10 @@ public class ApiConstants { public static final String SCHEDULED_DATE = "scheduleddate"; public static final String BACKUP_PROVIDER = "backupprovider"; + public static final String PRIVATE_MULTIQUEUE_NUMBER = "privatemultiqueuenumber"; + public static final String PUBLIC_MULTIQUEUE_NUMBER = "publicmultiqueuenumber"; + public static final String PRIVATE_GATEWAY_MULTIQUEUE_NUMBER = "privategatewaymultiqueuenumber"; + /** * This enum specifies IO Drivers, each option controls specific policies on I/O. * Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0). diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/NetworkOfferingBaseCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/NetworkOfferingBaseCmd.java index 9b42be137314..42ff4ad1943f 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/NetworkOfferingBaseCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/NetworkOfferingBaseCmd.java @@ -216,6 +216,16 @@ public abstract class NetworkOfferingBaseCmd extends BaseCmd { description = "the routing mode for the network offering. Supported types are: Static or Dynamic.") private String routingMode; + @Parameter(name = ApiConstants.PUBLIC_MULTIQUEUE_NUMBER, type = CommandType.INTEGER, since = "24.0", + description = "Multiqueue number for the public NIC of VRs belonging to guest networks. This parameter " + + "is not allowed for L2 network and isolated network for VPC (tier) offerings.") + private Integer publicMultiqueueNumber; + + @Parameter(name = ApiConstants.PRIVATE_MULTIQUEUE_NUMBER, type = CommandType.INTEGER, since = "24.0", + description = "Multiqueue number for the private NICs of VRs belonging to guest networks and VPC tiers. " + + "This parameter is not allowed for L2 network offerings") + private Integer privateMultiqueueNumber; + private Map sourceDetailsMap; ///////////////////////////////////////////////////// @@ -484,6 +494,14 @@ public String getRoutingMode() { return routingMode; } + public Integer getPublicMultiqueueNumber() { + return publicMultiqueueNumber; + } + + public Integer getPrivateMultiqueueNumber() { + return privateMultiqueueNumber; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java index 2b934a60da7a..865ec05f6a7f 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java @@ -165,6 +165,14 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { description = "True if the VPC offering is IP conserve mode enabled, allowing public IPs to be used across multiple VPC tiers. Default value is false") private Boolean conserveMode; + @Parameter(name = ApiConstants.PUBLIC_MULTIQUEUE_NUMBER, type = CommandType.INTEGER, since = "24.0", + description = "Multiqueue number for the public NIC of VRs belonging to VPCs.") + private Integer publicMultiqueueNumber; + + @Parameter(name = ApiConstants.PRIVATE_GATEWAY_MULTIQUEUE_NUMBER, type = CommandType.INTEGER, since = "24.0", + description = "Multiqueue number for the private gateway NIC of VRs belonging to VPCs.") + private Integer privateGatewayMultiqueueNumber; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -318,6 +326,14 @@ public boolean isConserveMode() { return BooleanUtils.toBoolean(conserveMode); } + public Integer getPublicMultiqueueNumber() { + return publicMultiqueueNumber; + } + + public Integer getPrivateGatewayMultiqueueNumber() { + return privateGatewayMultiqueueNumber; + } + @Override public void create() throws ResourceAllocationException { VpcOffering vpcOff = _vpcProvSvc.createVpcOffering(this); diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java index 740dd23604a9..d549eae6fbe2 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java @@ -171,6 +171,14 @@ public class NetworkOfferingResponse extends BaseResponseWithAnnotations { @Param(description = "the routing mode for the network offering, supported types are Static or Dynamic.") private String routingMode; + @SerializedName(ApiConstants.PUBLIC_MULTIQUEUE_NUMBER) + @Param(description = "Multiqueue number for the public NIC of VRs belonging to isolated networks.", since = "24.0") + private Integer publicMultiqueueNumber; + + @SerializedName(ApiConstants.PRIVATE_MULTIQUEUE_NUMBER) + @Param(description = "Multiqueue number for the private NICs of VRs belonging to isolated networks and VPC tiers.", since = "24.0") + private Integer privateMultiqueueNumber; + public void setId(String id) { this.id = id; } @@ -342,4 +350,12 @@ public String getServiceOfferingName() { public void setServiceOfferingName(String serviceOfferingName) { this.serviceOfferingName = serviceOfferingName; } + + public void setPublicMultiqueueNumber(Integer publicMultiqueueNumber) { + this.publicMultiqueueNumber = publicMultiqueueNumber; + } + + public void setPrivateMultiqueueNumber(Integer privateMultiqueueNumber) { + this.privateMultiqueueNumber = privateMultiqueueNumber; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/VpcOfferingResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/VpcOfferingResponse.java index 2e821dae52de..73a9b39eefbd 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/VpcOfferingResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/VpcOfferingResponse.java @@ -106,6 +106,14 @@ public class VpcOfferingResponse extends BaseResponse { @Param(description = "True if the VPC offering is IP conserve mode enabled, allowing public IP services to be used across multiple VPC tiers.", since = "4.23.0") private Boolean conserveMode; + @SerializedName(ApiConstants.PUBLIC_MULTIQUEUE_NUMBER) + @Param(description = "Multiqueue number for the public NIC of VRs belonging to VPCs.", since = "24.0") + private Integer publicMultiqueueNumber; + + @SerializedName(ApiConstants.PRIVATE_GATEWAY_MULTIQUEUE_NUMBER) + @Param(description = "Multiqueue number for the private gateway NIC of VRs belonging to VPCs.", since = "24.0") + private Integer privateGatewayMultiqueueNumber; + public void setId(String id) { this.id = id; } @@ -213,4 +221,12 @@ public Boolean getConserveMode() { public void setConserveMode(Boolean conserveMode) { this.conserveMode = conserveMode; } + + public void setPublicMultiqueueNumber(Integer publicMultiqueueNumber) { + this.publicMultiqueueNumber = publicMultiqueueNumber; + } + + public void setPrivateGatewayMultiqueueNumber(Integer privateGatewayMultiqueueNumber) { + this.privateGatewayMultiqueueNumber = privateGatewayMultiqueueNumber; + } } diff --git a/core/src/main/java/com/cloud/agent/api/PlugNicCommand.java b/core/src/main/java/com/cloud/agent/api/PlugNicCommand.java index 322b755b86a7..4435d3c66bda 100644 --- a/core/src/main/java/com/cloud/agent/api/PlugNicCommand.java +++ b/core/src/main/java/com/cloud/agent/api/PlugNicCommand.java @@ -25,21 +25,12 @@ import java.util.Map; public class PlugNicCommand extends Command { - NicTO nic; String instanceName; VirtualMachine.Type vmType; + private Integer targetVmCpus; Map details; - public NicTO getNic() { - return nic; - } - - @Override - public boolean executeInSequence() { - return true; - } - protected PlugNicCommand() { } @@ -56,6 +47,18 @@ public PlugNicCommand(NicTO nic, String instanceName, VirtualMachine.Type vmtype this.details = details; } + public PlugNicCommand(NicTO nic, String instanceName, VirtualMachine.Type vmtype, Integer targetVmCpus, Map details) { + this.nic = nic; + this.instanceName = instanceName; + this.vmType = vmtype; + this.targetVmCpus = targetVmCpus; + this.details = details; + } + + public NicTO getNic() { + return nic; + } + public String getVmName() { return instanceName; } @@ -67,4 +70,13 @@ public VirtualMachine.Type getVMType() { public Map getDetails() { return this.details; } + + public Integer getTargetVmCpus() { + return targetVmCpus; + } + + @Override + public boolean executeInSequence() { + return true; + } } diff --git a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java index 5909d098db8b..c0435b219c0b 100644 --- a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java +++ b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java @@ -174,7 +174,7 @@ NetworkOfferingVO createNetworkOffering(String name, String displayText, Traffic boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, Boolean forTungsten, boolean forNsx, boolean forNetris, NetworkOffering.NetworkMode networkMode, List domainIds, List zoneIds, boolean enableOffering, final NetUtils.InternetProtocol internetProtocol, - NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber); + NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber, Integer publicMultiqueueNumber, Integer privateMultiqueueNumber); Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, boolean forSystemVms, Long podId, String startIP, String endIP, String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr, Provider provider) 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 8c9a1653a260..0cc4b4fcb26a 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -1316,7 +1316,7 @@ protected void processPrepareExternalProvisioning(boolean firstStart, Host host, List nics = _nicsDao.listByVmId(vmProfile.getId()); NicTO[] nicTOs = new NicTO[nics.size()]; nics.forEach(nicVO -> { - NicTO nicTO = toNicTO(_networkModel.getNicProfile(vmProfile.getVirtualMachine(), nicVO, dataCenter), + NicTO nicTO = toNicTO(_networkModel.getNicProfile(vmProfile.getVirtualMachine(), nicVO, dataCenter, null), HypervisorType.External); nicTOs[nicTO.getDeviceId()] = nicTO; }); @@ -5161,8 +5161,8 @@ public boolean plugNic(final Network network, final NicTO nic, final VirtualMach ResourceUnavailableException, InsufficientCapacityException { boolean result = true; - final VMInstanceVO router = _vmDao.findById(vm.getId()); - if (router.getState() == State.Running) { + final VMInstanceVO targetVm = _vmDao.findById(vm.getId()); + if (targetVm.getState() == State.Running) { try { NetworkDetailVO pvlanTypeDetail = networkDetailsDao.findDetail(network.getId(), ApiConstants.ISOLATED_PVLAN_TYPE); if (pvlanTypeDetail != null) { @@ -5171,7 +5171,7 @@ public boolean plugNic(final Network network, final NicTO nic, final VirtualMach nicDetails.putIfAbsent(NetworkOffering.Detail.pvlanType, pvlanTypeDetail.getValue()); nic.setDetails(nicDetails); } - final PlugNicCommand plugNicCmd = new PlugNicCommand(nic, vm.getName(), vm.getType(), vm.getDetails()); + final PlugNicCommand plugNicCmd = new PlugNicCommand(nic, vm.getName(), vm.getType(), vm.getCpus(), vm.getDetails()); final Commands cmds = new Commands(Command.OnError.Stop); cmds.addCommand("plugnic", plugNicCmd); _agentMgr.send(dest.getHost().getId(), cmds); @@ -5184,11 +5184,11 @@ public boolean plugNic(final Network network, final NicTO nic, final VirtualMach throw new AgentUnavailableException("Unable to plug nic for router " + vm.getName() + " in network " + network, dest.getHost().getId(), e); } } else { - String message = String.format("Unable to apply PlugNic, VM [%s] is not in the right state (\"Running\"). VM state [%s].", router.toString(), router.getState()); + String message = String.format("Unable to plug NIC to VM [%s], as it is not in the right state (\"Running\"). VM state [%s].", targetVm, targetVm.getState()); logger.warn(message); throw new ResourceUnavailableException(message, DataCenter.class, - router.getDataCenterId()); + targetVm.getDataCenterId()); } return result; diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 8af75562b31c..70c2ce7de5ab 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -41,6 +41,9 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.network.guru.DirectNetworkGuru; +import com.cloud.network.guru.ExternalGuestNetworkGuru; +import com.cloud.network.vpc.VpcOfferingVO; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.annotation.AnnotationService; import org.apache.cloudstack.annotation.dao.AnnotationDao; @@ -603,27 +606,27 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { if (_networkOfferingDao.findByUniqueName(NetworkOffering.QuickCloudNoServices) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.QuickCloudNoServices, "Offering for QuickCloud with no services", TrafficType.Guest, null, true, Availability.Optional, null, new HashMap<>(), true, Network.GuestType.Shared, false, null, true, null, true, - false, null, false, null, true, false, false, false, false, null, null, null, true, null, null, false); + false, null, false, null, true, false, false, false, false, null, null, null, true, null, null, false, null, null); } //#2 - SG enabled network offering if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOfferingWithSGService) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOfferingWithSGService, "Offering for Shared Security group enabled networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, - null, true, false, null, false, null, true, false, false, false, false, null, null, null, true, null, null, false); + null, true, false, null, false, null, true, false, false, false, false, null, null, null, true, null, null, false, null, null); } //#3 - shared network offering with no SG service if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOffering, "Offering for Shared networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true, false, null, false, - null, true, false, false, false, false, null, null, null, true, null, null, false); + null, true, false, false, false, false, null, null, null, true, null, null, false, null, null); } if (_networkOfferingDao.findByUniqueName(NetworkOffering.DEFAULT_TUNGSTEN_SHARED_NETWORK_OFFERING_WITH_SGSERVICE) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DEFAULT_TUNGSTEN_SHARED_NETWORK_OFFERING_WITH_SGSERVICE, "Offering for Tungsten Shared Security group enabled networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultTungstenSharedSGEnabledNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, - null, true, false, null, false, null, true, false, true, false, false, null, null, null, true, null, null, false); + null, true, false, null, false, null, true, false, true, false, false, null, null, null, true, null, null, false, null, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -633,14 +636,14 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService, "Offering for Isolated networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Required, null, defaultIsolatedSourceNatEnabledNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, true, null, false, false, null, false, null, - true, false, false, false, false, null, null, null, true, null, null, false); + true, false, false, false, false, null, null, null, true, null, null, false, null, null); } //#5 - default vpc offering with LB service if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks, "Offering for Isolated VPC networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Optional, null, - defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, true, null, false, false, null, false, null, true, true, false, false, false, null, null, null, true, null, null, false); + defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, true, null, false, false, null, false, null, true, true, false, false, false, null, null, null, true, null, null, false, null, null); } //#6 - default vpc offering with no LB service @@ -649,14 +652,14 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { defaultVPCOffProviders.remove(Service.Lb); offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB, "Offering for Isolated VPC networks with Source Nat service enabled and LB service disabled", TrafficType.Guest, null, false, Availability.Optional, - null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false, null, null, null, true, null, null, false); + null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false, null, null, null, true, null, null, false, null, null); } //#7 - isolated offering with source nat disabled if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOffering, "Offering for Isolated networks with no Source Nat service", TrafficType.Guest, null, true, Availability.Optional, null, defaultIsolatedNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, - true, null, true, false, null, false, null, true, false, false, false, false, null, null, null, true, null, null, false); + true, null, true, false, null, false, null, true, false, false, false, false, null, null, null, true, null, null, false, null, null); } //#8 - network offering with internal lb service @@ -678,7 +681,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB, "Offering for Isolated VPC networks with Internal Lb support", TrafficType.Guest, null, false, Availability.Optional, null, internalLbOffProviders, - true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false, null, null, null, true, null, null, false); + true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false, null, null, null, true, null, null, false, null, null); offering.setInternalLb(true); offering.setPublicLb(false); _networkOfferingDao.update(offering.getId(), offering); @@ -709,7 +712,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedEIPandELBNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedEIPandELBNetworkOffering, "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, null, true, Availability.Optional, null, - netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true, false, false, false, false, null, null, null, true, null, null, false); + netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true, false, false, false, false, null, null, null, true, null, null, false, null, null); offering.setDedicatedLB(false); _networkOfferingDao.update(offering.getId(), offering); } @@ -2216,6 +2219,56 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { }); } + private void setGuestNetworkVrNicMultiqueueNumber(Pair networks, NetworkVO implementedNetwork, NicProfile nicProfile, List nics) { + if (networks == null) { + logger.debug("Skipping the assignment of multiqueue for VR because it is not related with any network."); + return; + } + + VpcVO vpcVO = networks.second(); + boolean isVpcVr = vpcVO != null; + if (isVpcVr) { + logger.trace("The multiqueue number for NICs of VPCs VRs is not defined at this step, skipping it."); + return; + } + + if (implementedNetwork.getTrafficType() == TrafficType.Control) { + logger.trace("The multiqueue number is not applied for NICs of control networks, skipping it."); + return; + } + + Integer multiqueueNumber = getGuestNetworkVrNicMultiqueueNumber(implementedNetwork.getTrafficType(), nics, nicProfile); + if (multiqueueNumber == null) { + logger.info("Multiqueue for NIC [{}] will not be defined because it was not possible to identify its corresponding network " + + "offering or the corresponding multiqueue attribute has not been defined in the offering."); + } else { + logger.info("Setting [{}] as the multiqueue for NIC [{}].", multiqueueNumber, nicProfile.getUuid()); + nicProfile.setMultiqueueNumber(multiqueueNumber); + } + } + + + private Integer getGuestNetworkVrNicMultiqueueNumber(TrafficType trafficType, List nics, NicProfile nicProfile) { + logger.debug("Fetching the network offering of the guest network associated with the VR with ID [{}].", nicProfile.getVirtualMachineId()); + NetworkOffering networkOfferingOfVrIsolatedNetwork = nics.stream() + .filter(nic -> ExternalGuestNetworkGuru.NETWORK_GURU_NAME.equals(nic.getReserver()) || DirectNetworkGuru.NETWORK_GURU_NAME.equals(nic.getReserver())) + .map(nic -> { + NetworkVO network = _entityMgr.findById(NetworkVO.class, nic.getNetworkId()); + return network == null ? null : _entityMgr.findByIdIncludingRemoved(NetworkOfferingVO.class, network.getNetworkOfferingId()); + }).filter(Objects::nonNull).findFirst().orElse(null); + + if (networkOfferingOfVrIsolatedNetwork == null) { + logger.info("Unable to identify the multiqueue value for NIC [{}], as it was not possible to find its corresponding network offering.", nicProfile.getUuid()); + return null; + } + + if (trafficType == TrafficType.Public) { + return networkOfferingOfVrIsolatedNetwork.getPublicMultiqueueNumber(); + } + + return networkOfferingOfVrIsolatedNetwork.getPrivateMultiqueueNumber(); + } + @Override public void prepare(final VirtualMachineProfile vmProfile, final DeployDestination dest, final ReservationContext context) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { @@ -2242,11 +2295,12 @@ public int compare(final NicVO nic1, final NicVO nic2) { throw new CloudRuntimeException(String.format("Failed to implement Network ID=%s as a part preparing NIC %s", network, nic)); } - final NetworkVO network = implemented.second(); - final NicProfile profile = prepareNic(vmProfile, dest, context, nic.getId(), network); + final NetworkVO implementedNetwork = implemented.second(); + final NicProfile profile = prepareNic(vmProfile, dest, context, nic.getId(), implementedNetwork); if (vmProfile.getType() == Type.DomainRouter) { Pair networks = getGuestNetworkRouterAndVpcDetails(vmProfile.getId()); - setMtuInVRNicProfile(networks, network.getTrafficType(), profile); + setMtuInVRNicProfile(networks, implementedNetwork.getTrafficType(), profile); + setGuestNetworkVrNicMultiqueueNumber(networks, implementedNetwork, profile, nics); } vmProfile.addNic(profile); } @@ -4614,18 +4668,56 @@ protected NicProfile getNicProfileForVm(final Network network, final NicProfile final NicVO nicVO = _nicDao.findByNetworkIdInstanceIdAndBroadcastUri(network.getId(), vm.getId(), broadcastUri); if (nicVO != null) { if (ipAddress == null || nicVO.getIPv4Address().equals(ipAddress)) { - nic = _networkModel.getNicProfile(vm, network.getId(), broadcastUri); + nic = _networkModel.getNicProfile(vm, network.getId(), broadcastUri, null); } } } else { final NicVO nicVO = _nicDao.findByNtwkIdAndInstanceId(network.getId(), vm.getId()); if (nicVO != null) { - nic = _networkModel.getNicProfile(vm, network.getId(), null); + nic = _networkModel.getNicProfile(vm, network.getId(), null, null); } } return nic; } + private Integer getVpcVrNicMultiqueueNumber(Network network, VirtualMachine vm) { + if (ExternalGuestNetworkGuru.NETWORK_GURU_NAME.equals(network.getGuruName())) { + NetworkOfferingVO networkOffering = _entityMgr.findByIdIncludingRemoved(NetworkOfferingVO.class, network.getNetworkOfferingId()); + if (networkOffering == null) { + logger.info("Unable to retrieve the multiqueue value for network [{}], as it was not possible to find its corresponding network offering.", network.getUuid()); + return null; + } + + if (!networkOffering.isForVpc()) { + logger.info("Network offering [{}] is not a tier offering. Skipping the retrieval of the new NIC's multiqueue number.", networkOffering.getUuid()); + return null; + } + + logger.debug("Network [{}] is a VPC tier; therefore, the private multiqueue number defined in its corresponding offering will be used.", network.getUuid()); + return networkOffering.getPrivateMultiqueueNumber(); + } + + DomainRouterVO router = routerDao.findById(vm.getId()); + if (router.getVpcId() == null) { + logger.info("The VR [{}] does not belong to a VPC. Skipping the retrieval of the new NIC's multiqueue number.", vm.getInstanceName()); + return null; + } + + VpcVO vpc = _entityMgr.findById(VpcVO.class, router.getVpcId()); + if (vpc == null) { + logger.info("Unable to find the VPC that the VR [{}] belongs to. Skipping the retrieval of the new NIC's multiqueue number.", vm.getInstanceName()); + return null; + } + + VpcOfferingVO vpcOffering = _entityMgr.findByIdIncludingRemoved(VpcOfferingVO.class, vpc.getVpcOfferingId()); + if (vpcOffering == null) { + logger.info("Unable to retrieve the multiqueue value for the private gateway's VR NIC, as it was not possible to find its VPC offering."); + return null; + } + + return vpcOffering.getPrivateGatewayMultiqueueNumber(); + } + @Override public NicProfile createNicForVm(final Network network, final NicProfile requested, final ReservationContext context, final VirtualMachineProfile vmProfile, final boolean prepare) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException, ConcurrentOperationException, InsufficientCapacityException, @@ -4668,6 +4760,14 @@ public NicProfile createNicForVm(final Network network, final NicProfile request logger.debug("NIC is prepared successfully for Instance {} in Network {}", vm, network); } + if (vm.getType() == Type.DomainRouter) { + Integer multiqueueNumber = getVpcVrNicMultiqueueNumber(network, vm); + if (multiqueueNumber != null) { + logger.info("Considering [{}] as the multiqueue number for the new NIC to be added to the VR [{}] corresponding to the network [{}].", multiqueueNumber, vm.getInstanceName(), network.getUuid()); + nic.setMultiqueueNumber(multiqueueNumber); + } + } + return nic; } diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java b/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java index b913468384e4..9ed22f115399 100644 --- a/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java +++ b/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java @@ -94,6 +94,12 @@ public class VpcOfferingVO implements VpcOffering { @Column(name = "conserve_mode") private boolean conserveMode; + @Column(name = "public_multiqueue_number") + private Integer publicMultiqueueNumber; + + @Column(name = "private_gateway_multiqueue_number") + private Integer privateGatewayMultiqueueNumber; + public VpcOfferingVO() { this.uuid = UUID.randomUUID().toString(); } @@ -109,12 +115,14 @@ public VpcOfferingVO(String name, String displayText, Long serviceOfferingId) { public VpcOfferingVO(final String name, final String displayText, final boolean isDefault, final Long serviceOfferingId, final boolean supportsDistributedRouter, final boolean offersRegionLevelVPC, - final boolean redundantRouter) { + final boolean redundantRouter, Integer publicMultiqueueNumber, Integer privateGatewayMultiqueueNumber) { this(name, displayText, serviceOfferingId); this.isDefault = isDefault; this.supportsDistributedRouter = supportsDistributedRouter; this.offersRegionLevelVPC = offersRegionLevelVPC; this.redundantRouter = redundantRouter; + this.publicMultiqueueNumber = publicMultiqueueNumber; + this.privateGatewayMultiqueueNumber = privateGatewayMultiqueueNumber; } public VpcOfferingVO(String name, String displayText, boolean isDefault, Long serviceOfferingId, @@ -254,4 +262,14 @@ public boolean isConserveMode() { public void setConserveMode(boolean conserveMode) { this.conserveMode = conserveMode; } + + @Override + public Integer getPublicMultiqueueNumber() { + return publicMultiqueueNumber; + } + + @Override + public Integer getPrivateGatewayMultiqueueNumber() { + return privateGatewayMultiqueueNumber; + } } diff --git a/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java b/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java index fc22e68985d2..ee22b95bc7fd 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java +++ b/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java @@ -176,6 +176,12 @@ public String getDisplayText() { @Column(name = "specify_as_number") private Boolean specifyAsNumber = false; + @Column(name = "public_multiqueue_number") + private Integer publicMultiqueueNumber; + + @Column(name = "private_multiqueue_number") + private Integer privateMultiqueueNumber; + @Override public boolean isKeepAliveEnabled() { return keepAliveEnabled; @@ -583,4 +589,22 @@ public Boolean isSpecifyAsNumber() { public void setSpecifyAsNumber(Boolean specifyAsNumber) { this.specifyAsNumber = specifyAsNumber; } + + @Override + public Integer getPublicMultiqueueNumber() { + return publicMultiqueueNumber; + } + + public void setPublicMultiqueueNumber(Integer publicMultiqueueNumber) { + this.publicMultiqueueNumber = publicMultiqueueNumber; + } + + @Override + public Integer getPrivateMultiqueueNumber() { + return privateMultiqueueNumber; + } + + public void setPrivateMultiqueueNumber(Integer privateMultiqueueNumber) { + this.privateMultiqueueNumber = privateMultiqueueNumber; + } } diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42300to2400.sql b/engine/schema/src/main/resources/META-INF/db/schema-42300to2400.sql index 863ee93bc01a..8732ad6baafa 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-42300to2400.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-42300to2400.sql @@ -100,3 +100,11 @@ CREATE TABLE IF NOT EXISTS `cloud`.`instance_boot_group_details` ( PRIMARY KEY (`id`), CONSTRAINT `fk_instance_boot_group_details__group_id` FOREIGN KEY (`boot_group_id`) REFERENCES `instance_boot_group` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Multiqueue for VRs +-- Add 'public_multiqueue_number' and 'private_multiqueue_number' columns to the 'cloud.network_offerings' table +CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.network_offerings', 'public_multiqueue_number', 'INT DEFAULT NULL'); +CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.network_offerings', 'private_multiqueue_number', 'INT DEFAULT NULL'); +-- Add 'public_multiqueue_number' and 'private_gateway_multiqueue_number' columns to the 'cloud.vpc_offerings' table +CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings', 'public_multiqueue_number', 'INT DEFAULT NULL'); +CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings', 'private_gateway_multiqueue_number', 'INT DEFAULT NULL'); diff --git a/engine/schema/src/main/resources/META-INF/db/views/cloud.network_offering_view.sql b/engine/schema/src/main/resources/META-INF/db/views/cloud.network_offering_view.sql index 368566c32b32..6d743402e94c 100644 --- a/engine/schema/src/main/resources/META-INF/db/views/cloud.network_offering_view.sql +++ b/engine/schema/src/main/resources/META-INF/db/views/cloud.network_offering_view.sql @@ -63,6 +63,8 @@ SELECT `network_offerings`.`service_package_id` AS `service_package_id`, `network_offerings`.`routing_mode` AS `routing_mode`, `network_offerings`.`specify_as_number` AS `specify_as_number`, + `network_offerings`.`public_multiqueue_number` AS `public_multiqueue_number`, + `network_offerings`.`private_multiqueue_number` AS `private_multiqueue_number`, GROUP_CONCAT(DISTINCT(domain.id)) AS domain_id, GROUP_CONCAT(DISTINCT(domain.uuid)) AS domain_uuid, GROUP_CONCAT(DISTINCT(domain.name)) AS domain_name, diff --git a/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql b/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql index 3669bb10122b..e2bf3e24174c 100644 --- a/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql +++ b/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql @@ -39,6 +39,8 @@ select `vpc_offerings`.`routing_mode` AS `routing_mode`, `vpc_offerings`.`specify_as_number` AS `specify_as_number`, `vpc_offerings`.`conserve_mode` AS `conserve_mode`, + `vpc_offerings`.`public_multiqueue_number` AS `public_multiqueue_number`, + `vpc_offerings`.`private_gateway_multiqueue_number` AS `private_gateway_multiqueue_number`, group_concat(distinct `domain`.`id` separator ',') AS `domain_id`, group_concat(distinct `domain`.`uuid` separator ',') AS `domain_uuid`, group_concat(distinct `domain`.`name` separator ',') AS `domain_name`, 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 9009ec629ca3..eb020246f3fb 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 @@ -4105,9 +4105,7 @@ private void createVif(final LibvirtVMDef vm, final VirtualMachineTO vmSpec, fin throw new InternalErrorException("LibvirtVMDef object get devices with null result"); } final InterfaceDef interfaceDef = getVifDriver(nic.getType(), nic.getName()).plug(nic, vm.getPlatformEmulator(), nicAdapter, extraConfig); - if (vmSpec.getDetails() != null) { - setInterfaceDefQueueSettings(vmSpec.getDetails(), vmSpec.getCpus(), interfaceDef); - } + setInterfaceDefQueueSettings(vmSpec.getDetails(), vmSpec.getCpus(), interfaceDef, nic.getMultiqueueNumber(), vmSpec.getType() == VirtualMachine.Type.DomainRouter); vm.getDevices().addDevice(interfaceDef); } @@ -6839,22 +6837,43 @@ protected void deleteIfExists(String snapshotPath) { } } - public void setInterfaceDefQueueSettings(Map details, Integer cpus, InterfaceDef interfaceDef) { + private Integer getMultiqueueFromVmDetails(Map details) { 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); - } + return Integer.valueOf(nicMultiqueueNumber); } catch (NumberFormatException ex) { - LOGGER.warn(String.format("VM details %s is not a valid integer value %s", VmDetailConstants.NIC_MULTIQUEUE_NUMBER, nicMultiqueueNumber)); + logger.warn("VM detail [{}] is not a valid integer value {}.", VmDetailConstants.NIC_MULTIQUEUE_NUMBER, nicMultiqueueNumber); } } + + return null; + } + + public void setInterfaceDefQueueSettings(Map details, Integer cpus, InterfaceDef interfaceDef, Integer multiqueueForVrs, boolean isVr) { + if (details == null) { + details = new HashMap<>(); + } + + Integer nicMultiqueueNumber = getMultiqueueFromVmDetails(details); + if (nicMultiqueueNumber != null) { + logger.info("VM detail [{}] is equal to [{}]; therefore, it will be used as the multiqueue value.", VmDetailConstants.NIC_MULTIQUEUE_NUMBER, nicMultiqueueNumber); + } else if (isVr && multiqueueForVrs != null) { + logger.info("VM detail [{}] has not been specified. The target VM is a VR and it has an associated multiqueue number. " + + "Considering this associated value, equal to [{}], as the multiqueue value.", VmDetailConstants.NIC_MULTIQUEUE_NUMBER, multiqueueForVrs); + nicMultiqueueNumber = multiqueueForVrs; + } + + if (nicMultiqueueNumber != null) { + if (nicMultiqueueNumber == InterfaceDef.MULTI_QUEUE_NUMBER_MEANS_CPU_CORES && cpus != null && cpus > 0) { + logger.info("The NIC multiqueue number is equal to [{}]. Thus, defining the multiqueue value as the number of vCPUs [{}].", InterfaceDef.MULTI_QUEUE_NUMBER_MEANS_CPU_CORES, cpus); + interfaceDef.setMultiQueueNumber(cpus); + } else { + logger.debug("Defining the NIC multiqueue number as [{}] in the NIC XML definition.", nicMultiqueueNumber); + interfaceDef.setMultiQueueNumber(nicMultiqueueNumber); + } + } + String nicPackedEnabled = details.get(VmDetailConstants.NIC_PACKED_VIRTQUEUES_ENABLED); if (nicPackedEnabled != null) { try { 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 b0950376a93d..6e02bfceeed1 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 @@ -62,9 +62,7 @@ public Answer execute(final PlugNicCommand command, final LibvirtComputingResour } 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); - } + libvirtComputingResource.setInterfaceDefQueueSettings(command.getDetails(), command.getTargetVmCpus(), interfaceDef, nic.getMultiqueueNumber(), vmType == VirtualMachine.Type.DomainRouter); 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 f7ca79127dad..aa332f047d8b 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 @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; +import com.cloud.vm.VirtualMachine; import org.apache.cloudstack.storage.configdrive.ConfigDrive; import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.commons.collections.MapUtils; @@ -79,9 +80,7 @@ public Answer execute(final PrepareForMigrationCommand command, final LibvirtCom 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); - } + libvirtComputingResource.setInterfaceDefQueueSettings(vm.getDetails(), vm.getCpus(), interfaceDef, nic.getMultiqueueNumber(), vm.getType() == VirtualMachine.Type.DomainRouter); 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 f22cfd2a96f9..c927c44dd2d3 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 @@ -19,6 +19,7 @@ import java.util.List; +import com.cloud.vm.VirtualMachine; import org.libvirt.Connect; import org.libvirt.Domain; import org.libvirt.LibvirtException; @@ -64,9 +65,7 @@ public Answer execute(final ReplugNicCommand command, final LibvirtComputingReso 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); - } + libvirtComputingResource.setInterfaceDefQueueSettings(command.getDetails(), null, interfaceDef, nic.getMultiqueueNumber(), command.getVMType() == VirtualMachine.Type.DomainRouter); interfaceDef.setSlot(oldPluggedNic.getSlot()); interfaceDef.setDevName(oldPluggedNic.getDevName()); interfaceDef.setLinkStateUp(false); diff --git a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java index 8badb916eeda..53b0e1e165df 100644 --- a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java +++ b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java @@ -217,7 +217,7 @@ private NetworkOffering locatePublicNetworkOffering(String offeringName, ConfigurationManager configMgr = (ConfigurationManager) _configService; NetworkOfferingVO voffer = configMgr.createNetworkOffering(offeringName, offeringDisplayText, TrafficType.Public, null, true, Availability.Optional, null, serviceProviderMap, true, - Network.GuestType.Shared, false, null, false, null, true, false, null, true, null, false, false, false, false, false, null, null, null, true, null, null, false); + Network.GuestType.Shared, false, null, false, null, true, false, null, true, null, false, false, false, false, false, null, null, null, true, null, null, false, null, null); long id = voffer.getId(); _networkOfferingDao.update(id, voffer); return _networkOfferingDao.findById(id); @@ -252,7 +252,7 @@ private NetworkOffering locateNetworkOffering(String offeringName, ConfigurationManager configMgr = (ConfigurationManager)_configService; NetworkOfferingVO voffer = configMgr.createNetworkOffering(offeringName, offeringDisplayText, TrafficType.Guest, null, false, Availability.Optional, null, serviceProviderMap, true, - Network.GuestType.Isolated, false, null, false, null, false, true, null, true, null, false, offeringName.equals(vpcRouterOfferingName), false, false, false, null, null, null, true, null, null, false); + Network.GuestType.Isolated, false, null, false, null, false, true, null, true, null, false, offeringName.equals(vpcRouterOfferingName), false, false, false, null, null, null, true, null, null, false, null, null); if (offeringName.equals(vpcRouterOfferingName)) { voffer.setInternalLb(true); } @@ -293,7 +293,7 @@ private VpcOffering locateVpcOffering() { } serviceProviderMap.put(svc, providerSet); } - vpcOffer = _vpcProvSvc.createVpcOffering(juniperVPCOfferingName, juniperVPCOfferingDisplayText, services, serviceProviderMap, null, null, null, null, null, null, null, VpcOffering.State.Enabled, null, false, false); + vpcOffer = _vpcProvSvc.createVpcOffering(juniperVPCOfferingName, juniperVPCOfferingDisplayText, services, serviceProviderMap, null, null, null, null, null, null, null, VpcOffering.State.Enabled, null, false, false, null, null); long id = vpcOffer.getId(); _vpcOffDao.update(id, (VpcOfferingVO)vpcOffer); return _vpcOffDao.findById(id); diff --git a/server/src/main/java/com/cloud/api/query/dao/NetworkOfferingJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/NetworkOfferingJoinDaoImpl.java index 22b51f6fd8c5..e6e933578a47 100644 --- a/server/src/main/java/com/cloud/api/query/dao/NetworkOfferingJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/NetworkOfferingJoinDaoImpl.java @@ -108,6 +108,8 @@ public NetworkOfferingResponse newNetworkOfferingResponse(NetworkOffering offeri networkOfferingResponse.setSupportsPublicAccess(offering.isSupportingPublicAccess()); networkOfferingResponse.setSupportsInternalLb(offering.isInternalLb()); networkOfferingResponse.setCreated(offering.getCreated()); + networkOfferingResponse.setPublicMultiqueueNumber(offering.getPublicMultiqueueNumber()); + networkOfferingResponse.setPrivateMultiqueueNumber(offering.getPrivateMultiqueueNumber()); if (offering.getGuestType() != null) { networkOfferingResponse.setGuestIpType(offering.getGuestType().toString()); } diff --git a/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java index e7fe07a18c78..5f4df7d2fd65 100644 --- a/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java @@ -71,6 +71,8 @@ public VpcOfferingResponse newVpcOfferingResponse(VpcOffering offering) { offeringResponse.setSupportsDistributedRouter(offering.isSupportsDistributedRouter()); offeringResponse.setSupportsRegionLevelVpc(offering.isOffersRegionLevelVPC()); offeringResponse.setCreated(offering.getCreated()); + offeringResponse.setPublicMultiqueueNumber(offering.getPublicMultiqueueNumber()); + offeringResponse.setPrivateGatewayMultiqueueNumber(offering.getPrivateGatewayMultiqueueNumber()); if (offering.getRoutingMode() != null) { offeringResponse.setRoutingMode(offering.getRoutingMode().toString()); } diff --git a/server/src/main/java/com/cloud/api/query/vo/NetworkOfferingJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/NetworkOfferingJoinVO.java index 40940736bbb9..a11381286f3d 100644 --- a/server/src/main/java/com/cloud/api/query/vo/NetworkOfferingJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/NetworkOfferingJoinVO.java @@ -192,6 +192,12 @@ public class NetworkOfferingJoinVO extends BaseViewVO implements NetworkOffering @Column(name = "specify_as_number") private Boolean specifyAsNumber; + @Column(name = "public_multiqueue_number") + private Integer publicMultiqueueNumber; + + @Column(name = "private_multiqueue_number") + private Integer privateMultiqueueNumber; + public NetworkOfferingJoinVO() { } @@ -452,4 +458,14 @@ public Boolean isSpecifyAsNumber() { public void setSpecifyAsNumber(Boolean specifyAsNumber) { this.specifyAsNumber = specifyAsNumber; } + + @Override + public Integer getPublicMultiqueueNumber() { + return publicMultiqueueNumber; + } + + @Override + public Integer getPrivateMultiqueueNumber() { + return privateMultiqueueNumber; + } } diff --git a/server/src/main/java/com/cloud/api/query/vo/VpcOfferingJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/VpcOfferingJoinVO.java index 9d65c19479fb..0d0d849474f1 100644 --- a/server/src/main/java/com/cloud/api/query/vo/VpcOfferingJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/VpcOfferingJoinVO.java @@ -115,6 +115,12 @@ public class VpcOfferingJoinVO implements VpcOffering { @Column(name = "conserve_mode") private boolean conserveMode; + @Column(name = "public_multiqueue_number") + private Integer publicMultiqueueNumber; + + @Column(name = "private_gateway_multiqueue_number") + private Integer privateGatewayMultiqueueNumber; + public VpcOfferingJoinVO() { } @@ -246,6 +252,16 @@ public String getInternetProtocol() { return internetProtocol; } + @Override + public Integer getPublicMultiqueueNumber() { + return publicMultiqueueNumber; + } + + @Override + public Integer getPrivateGatewayMultiqueueNumber() { + return privateGatewayMultiqueueNumber; + } + @Override public String toString() { StringBuilder buf = new StringBuilder("[VPC Offering ["); diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index c68dc390df2a..37e7ee77ac1c 100644 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -150,6 +150,7 @@ import org.apache.cloudstack.vm.lease.VMLeaseManager; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -7248,6 +7249,8 @@ public NetworkOffering createNetworkOffering(final NetworkOfferingBaseCmd cmd) { _networkSvc.validateIfServiceOfferingIsActiveAndSystemVmTypeIsDomainRouter(serviceOfferingId); } + validateNetworkOfferingMultiqueueParameters(cmd.getPublicMultiqueueNumber(), cmd.getPrivateMultiqueueNumber(), guestType, BooleanUtils.isTrue(forVpc)); + NetworkOffering.RoutingMode routingMode = verifyRoutingMode(routingModeString); // configure service provider map @@ -7460,7 +7463,8 @@ public NetworkOffering createNetworkOffering(final NetworkOfferingBaseCmd cmd) { } final NetworkOfferingVO offering = createNetworkOffering(name, displayText, trafficType, tags, specifyVlan, availability, networkRate, serviceProviderMap, false, guestType, false, - serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent, details, egressDefaultPolicy, maxconn, enableKeepAlive, forVpc, forTungsten, forNsx, forNetris, networkMode, domainIds, zoneIds, enable, internetProtocol, routingMode, specifyAsNumber); + serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent, details, egressDefaultPolicy, maxconn, enableKeepAlive, forVpc, forTungsten, forNsx, + forNetris, networkMode, domainIds, zoneIds, enable, internetProtocol, routingMode, specifyAsNumber, cmd.getPublicMultiqueueNumber(), cmd.getPrivateMultiqueueNumber()); if (Boolean.TRUE.equals(forNsx) && nsxSupportInternalLbSvc) { offering.setInternalLb(true); offering.setPublicLb(false); @@ -7471,6 +7475,26 @@ public NetworkOffering createNetworkOffering(final NetworkOfferingBaseCmd cmd) { return offering; } + private void validateNetworkOfferingMultiqueueParameters(Integer publicMultiqueueNumber, Integer privateMultiqueueNumber, GuestType guestType, boolean forVpc) { + if (guestType == GuestType.L2 && ObjectUtils.anyNotNull(publicMultiqueueNumber, privateMultiqueueNumber)) { + throw new InvalidParameterValueException("Multiqueue parameters cannot be specified for L2 network offerings."); + } + + if (publicMultiqueueNumber != null) { + if (forVpc) { + throw new InvalidParameterValueException(String.format("The [%s] parameter cannot be specified for offerings that are meant to be used for VPC tiers.", ApiConstants.PUBLIC_MULTIQUEUE_NUMBER)); + } + + if (publicMultiqueueNumber <= 0 && publicMultiqueueNumber != -1) { + throw new InvalidParameterValueException(String.format("The only non-positive value accepted by the parameter [%s] is [-1].", ApiConstants.PUBLIC_MULTIQUEUE_NUMBER)); + } + } + + if (privateMultiqueueNumber != null && privateMultiqueueNumber <= 0 && privateMultiqueueNumber != -1) { + throw new InvalidParameterValueException(String.format("The only non-positive value accepted by the parameter [%s] is [-1].", ApiConstants.PRIVATE_MULTIQUEUE_NUMBER)); + } + } + public static NetworkOffering.RoutingMode verifyRoutingMode(String routingModeString) { NetworkOffering.RoutingMode routingMode = null; if (routingModeString != null) { @@ -7628,7 +7652,7 @@ public NetworkOfferingVO createNetworkOffering(final String name, final String d final boolean conserveMode, final Map> serviceCapabilityMap, final boolean specifyIpRanges, final boolean isPersistent, final Map details, final boolean egressDefaultPolicy, final Integer maxconn, final boolean enableKeepAlive, Boolean forVpc, Boolean forTungsten, boolean forNsx, boolean forNetris, NetworkOffering.NetworkMode networkMode, final List domainIds, final List zoneIds, final boolean enableOffering, final NetUtils.InternetProtocol internetProtocol, - final NetworkOffering.RoutingMode routingMode, final boolean specifyAsNumber) { + final NetworkOffering.RoutingMode routingMode, final boolean specifyAsNumber, Integer publicMultiqueueNumber, Integer privateMultiqueueNumber) { String servicePackageUuid; String spDescription = null; @@ -7859,6 +7883,9 @@ public NetworkOfferingVO createNetworkOffering(final String name, final String d } offeringFinal.setNetworkMode(networkMode); + offeringFinal.setPublicMultiqueueNumber(publicMultiqueueNumber); + offeringFinal.setPrivateMultiqueueNumber(privateMultiqueueNumber); + if (enableOffering) { offeringFinal.setState(NetworkOffering.State.Enabled); } @@ -8610,6 +8637,8 @@ private void applyResolvedValuesToCommand(CloneNetworkOfferingCmd cmd, NetworkOf applyIfNotProvided(cmd, requestParams, "serviceOfferingId", ApiConstants.SERVICE_OFFERING_ID, cmd.getServiceOfferingId(), sourceOffering.getServiceOfferingId()); applyIfNotProvided(cmd, requestParams, "guestIptype", ApiConstants.GUEST_IP_TYPE, cmd.getGuestIpType(), sourceOffering.getGuestType().toString()); applyIfNotProvided(cmd, requestParams, "maxConnections", ApiConstants.MAX_CONNECTIONS, cmd.getMaxconnections(), sourceOffering.getConcurrentConnections()); + applyIfNotProvided(cmd, requestParams, "publicMultiqueueNumber", ApiConstants.PUBLIC_MULTIQUEUE_NUMBER, cmd.getPublicMultiqueueNumber(), sourceOffering.getPublicMultiqueueNumber()); + applyIfNotProvided(cmd, requestParams, "privateMultiqueueNumber", ApiConstants.PRIVATE_MULTIQUEUE_NUMBER, cmd.getPrivateMultiqueueNumber(), sourceOffering.getPrivateMultiqueueNumber()); applyBooleanIfNotProvided(cmd, requestParams, "specifyVlan", ApiConstants.SPECIFY_VLAN, sourceOffering.isSpecifyVlan()); applyBooleanIfNotProvided(cmd, requestParams, "conserveMode", ApiConstants.CONSERVE_MODE, sourceOffering.isConserveMode()); diff --git a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java index 943d1e73c4b5..f3b8c654ee02 100644 --- a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java @@ -207,6 +207,7 @@ public NicTO toNicTO(NicProfile profile) { to.setIp6Dns2(profile.getIPv6Dns2()); to.setNetworkId(profile.getNetworkId()); to.setEnabled(profile.isEnabled()); + to.setMultiqueueNumber(profile.getMultiqueueNumber()); NetworkVO network = networkDao.findById(profile.getNetworkId()); to.setNetworkUuid(network.getUuid()); diff --git a/server/src/main/java/com/cloud/network/NetworkModelImpl.java b/server/src/main/java/com/cloud/network/NetworkModelImpl.java index f47046cdc434..8ca823cccf09 100644 --- a/server/src/main/java/com/cloud/network/NetworkModelImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkModelImpl.java @@ -2476,7 +2476,7 @@ protected Long getNonGuestNetworkPhysicalNetworkId(Network network) { } @Override - public NicProfile getNicProfile(VirtualMachine vm, long networkId, String broadcastUri) { + public NicProfile getNicProfile(VirtualMachine vm, long networkId, String broadcastUri, Integer multiqueueNumber) { NicVO nic = null; if (broadcastUri != null) { nic = _nicDao.findByNetworkIdInstanceIdAndBroadcastUri(networkId, vm.getId(), broadcastUri); @@ -2487,11 +2487,11 @@ public NicProfile getNicProfile(VirtualMachine vm, long networkId, String broadc return null; } DataCenter dc = _dcDao.findById(vm.getDataCenterId()); - return getNicProfile(vm, nic, dc); + return getNicProfile(vm, nic, dc, multiqueueNumber); } @Override - public NicProfile getNicProfile(VirtualMachine vm, Nic nic, DataCenter dataCenter) { + public NicProfile getNicProfile(VirtualMachine vm, Nic nic, DataCenter dataCenter, Integer multiqueueNumber) { NetworkVO network = _networksDao.findById(nic.getNetworkId()); Integer networkRate = getNetworkRate(network.getId(), vm.getId()); NicProfile profile = @@ -2509,6 +2509,8 @@ public NicProfile getNicProfile(VirtualMachine vm, Nic nic, DataCenter dataCente Pair ip6Dns = getNetworkIp6Dns(network, dataCenter); profile.setIPv6Dns1(ip6Dns.first()); profile.setIPv6Dns2(ip6Dns.second()); + + profile.setMultiqueueNumber(multiqueueNumber); return profile; } diff --git a/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java b/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java index 99f8d8f697b2..944f6ba673f4 100644 --- a/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java +++ b/server/src/main/java/com/cloud/network/element/VpcVirtualRouterElement.java @@ -644,7 +644,7 @@ public boolean applyACLItemsToPrivateGw(final PrivateGateway gateway, final List boolean result = true; for (final DomainRouterVO domainRouterVO : routers) { - final NicProfile nicProfile = _networkModel.getNicProfile(domainRouterVO, privateNetwork.getId(), null); + final NicProfile nicProfile = _networkModel.getNicProfile(domainRouterVO, privateNetwork.getId(), null, null); if (nicProfile != null) { result = result && networkTopology.applyNetworkACLs(network, rules, domainRouterVO, isPrivateGateway); } else { diff --git a/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java index 5c0c4eed7fc4..af216198f5fa 100644 --- a/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/DirectNetworkGuru.java @@ -108,6 +108,8 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { private static final TrafficType[] TrafficTypes = {TrafficType.Guest}; protected IsolationMethod[] _isolationMethods; + public static final String NETWORK_GURU_NAME = "DirectNetworkGuru"; + @Override public boolean isMyTrafficType(TrafficType type) { for (TrafficType t : TrafficTypes) { diff --git a/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java index 49404068051c..d1a0d255abde 100644 --- a/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java @@ -88,6 +88,8 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { @Inject FirewallRulesCidrsDao _fwRulesCidrDao; + public static final String NETWORK_GURU_NAME = "ExternalGuestNetworkGuru"; + public ExternalGuestNetworkGuru() { super(); _isolationMethods = new IsolationMethod[] {new IsolationMethod("GRE"), new IsolationMethod("L3"), new IsolationMethod("VLAN")}; diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 58b2892e09c3..68e5dc0ed5eb 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -689,7 +689,7 @@ public void createNetworkACLsCommands(final List rules } } - NicTO nicTO = _networkHelper.getNicTO(router, guestNetworkId, null); + NicTO nicTO = _networkHelper.getNicTO(router, guestNetworkId, null, null); final SetNetworkACLCommand cmd = new SetNetworkACLCommand(rulesTO, nicTO); cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId())); cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, _routerControlHelper.getRouterIpInNetwork(guestNetworkId, router.getId())); @@ -1255,7 +1255,7 @@ public SetupGuestNetworkCommand createSetupGuestNetworkCommand(final DomainRoute final String networkDomain = network.getNetworkDomain(); final String dhcpRange = getGuestDhcpRange(guestNic, network, _entityMgr.findById(DataCenter.class, network.getDataCenterId())); - final NicProfile nicProfile = _networkModel.getNicProfile(router, nic.getNetworkId(), null); + final NicProfile nicProfile = _networkModel.getNicProfile(router, nic.getNetworkId(), null, null); final SetupGuestNetworkCommand setupCmd = new SetupGuestNetworkCommand(dhcpRange, networkDomain, router.getIsRedundantRouter(), defaultDns1, defaultDns2, add, _itMgr.toNicTO(nicProfile, router.getHypervisorType())); diff --git a/server/src/main/java/com/cloud/network/router/NetworkHelper.java b/server/src/main/java/com/cloud/network/router/NetworkHelper.java index c9daa5eedb47..cfe699ef9256 100644 --- a/server/src/main/java/com/cloud/network/router/NetworkHelper.java +++ b/server/src/main/java/com/cloud/network/router/NetworkHelper.java @@ -52,8 +52,7 @@ public abstract void handleSingleWorkingRedundantRouter( List disconnectedRouters, String reason) throws ResourceUnavailableException; - public abstract NicTO getNicTO(VirtualRouter router, Long networkId, - String broadcastUri); + public abstract NicTO getNicTO(VirtualRouter router, Long networkId, String broadcastUri, Integer multiqueueNumber); public abstract VirtualRouter destroyRouter(long routerId, Account caller, Long callerUserId) throws ResourceUnavailableException, diff --git a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java index 56534a8ee7df..c73094e76926 100644 --- a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java +++ b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java @@ -259,8 +259,8 @@ public void handleSingleWorkingRedundantRouter(final List details = new HashMap(); - - if(profile.getHypervisorType() == Hypervisor.HypervisorType.VMware){ + Map details = new HashMap<>(); + VirtualMachineTO vmTO = null; + if (profile.getHypervisorType() == Hypervisor.HypervisorType.VMware || profile.getHypervisorType() == Hypervisor.HypervisorType.KVM) { HypervisorGuru hvGuru = _hvGuruMgr.getGuru(profile.getHypervisorType()); - VirtualMachineTO vmTO = hvGuru.implement(profile); - if(vmTO.getDetails() != null){ + vmTO = hvGuru.implement(profile); + if (vmTO.getDetails() != null) { details = vmTO.getDetails(); } } @@ -397,6 +399,9 @@ public boolean finalizeCommandsOnStart(final Commands cmds, final VirtualMachine return super.finalizeCommandsOnStart(cmds, profile); } + VpcVO vpc = _vpcDao.findById(domainRouterVO.getVpcId()); + VpcOfferingVO vpcOffering = _entityMgr.findByIdIncludingRemoved(VpcOfferingVO.class, vpc.getVpcOfferingId()); + if (domainRouterVO.getState() == State.Starting || domainRouterVO.getState() == State.Running) { // 1) FORM SSH CHECK COMMAND final NicProfile controlNic = getControlNic(profile); @@ -462,10 +467,9 @@ public boolean finalizeCommandsOnStart(final Commands cmds, final VirtualMachine } } String broadcastURI = publicNic.getBroadcastUri() != null ? publicNic.getBroadcastUri().toString() : null; - final PlugNicCommand plugNicCmd = new PlugNicCommand(_nwHelper.getNicTO(domainRouterVO, publicNic.getNetworkId(), broadcastURI), - domainRouterVO.getInstanceName(), domainRouterVO.getType(), details); + final PlugNicCommand plugNicCmd = new PlugNicCommand(_nwHelper.getNicTO(domainRouterVO, publicNic.getNetworkId(), broadcastURI, vpcOffering.getPublicMultiqueueNumber()), + domainRouterVO.getInstanceName(), domainRouterVO.getType(), vmTO != null ? vmTO.getCpus() : null, details); cmds.addCommand(plugNicCmd); - final VpcVO vpc = _vpcDao.findById(domainRouterVO.getVpcId()); if (routedIpv4Manager.isRoutedVpc(vpc)) { continue; } @@ -490,7 +494,8 @@ public boolean finalizeCommandsOnStart(final Commands cmds, final VirtualMachine final Nic guestNic = updateNicWithDeviceId(nicNtwk.first().getId(), deviceId); deviceId ++; // plug guest nic - final PlugNicCommand plugNicCmd = new PlugNicCommand(_nwHelper.getNicTO(domainRouterVO, guestNic.getNetworkId(), null), domainRouterVO.getInstanceName(), domainRouterVO.getType(), details); + final PlugNicCommand plugNicCmd = new PlugNicCommand(_nwHelper.getNicTO(domainRouterVO, guestNic.getNetworkId(), null, vpcOffering.getPrivateGatewayMultiqueueNumber()), + domainRouterVO.getInstanceName(), domainRouterVO.getType(), vmTO != null ? vmTO.getCpus() : null, details); cmds.addCommand(plugNicCmd); // set private network final PrivateIpVO ipVO = _privateIpDao.findByIpAndSourceNetworkId(guestNic.getNetworkId(), guestNic.getIPv4Address()); @@ -520,11 +525,13 @@ public boolean finalizeCommandsOnStart(final Commands cmds, final VirtualMachine final Nic guestNic = updateNicWithDeviceId(nicNtwk.first().getId(), deviceId); deviceId ++; // plug guest nic - final PlugNicCommand plugNicCmd = new PlugNicCommand(_nwHelper.getNicTO(domainRouterVO, guestNic.getNetworkId(), null), domainRouterVO.getInstanceName(), domainRouterVO.getType(), details); + NetworkOffering tierOffering = _entityMgr.findByIdIncludingRemoved(NetworkOffering.class, nicNtwk.second().getNetworkOfferingId()); + final PlugNicCommand plugNicCmd = new PlugNicCommand(_nwHelper.getNicTO(domainRouterVO, guestNic.getNetworkId(), null, tierOffering.getPrivateMultiqueueNumber()), + domainRouterVO.getInstanceName(), domainRouterVO.getType(), vmTO != null ? vmTO.getCpus() : null, details); cmds.addCommand(plugNicCmd); // set guest network final VirtualMachine vm = _vmDao.findById(domainRouterVO.getId()); - final NicProfile nicProfile = _networkModel.getNicProfile(vm, guestNic.getNetworkId(), null); + final NicProfile nicProfile = _networkModel.getNicProfile(vm, guestNic.getNetworkId(), null, null); final SetupGuestNetworkCommand setupCmd = _commandSetupHelper.createSetupGuestNetworkCommand(domainRouterVO, true, nicProfile); cmds.addCommand(setupCmd); } @@ -749,7 +756,7 @@ public boolean destroyPrivateGateway(final PrivateGateway gateway, final Virtual } final Network privateNetwork = _networkModel.getNetwork(gateway.getNetworkId()); - final NicProfile nicProfile = _networkModel.getNicProfile(router, privateNetwork.getId(), null); + final NicProfile nicProfile = _networkModel.getNicProfile(router, privateNetwork.getId(), null, null); logger.debug("Releasing private ip for gateway " + gateway + " from " + router); result = setupVpcPrivateNetwork(router, false, nicProfile); diff --git a/server/src/main/java/com/cloud/network/rules/PrivateGatewayRules.java b/server/src/main/java/com/cloud/network/rules/PrivateGatewayRules.java index 8e70e4ec3a86..ec12d7ed8f9f 100644 --- a/server/src/main/java/com/cloud/network/rules/PrivateGatewayRules.java +++ b/server/src/main/java/com/cloud/network/rules/PrivateGatewayRules.java @@ -124,7 +124,7 @@ protected boolean destroyPrivateGateway(final NetworkTopologyVisitor visitor) th logger.debug("Releasing private ip for gateway " + _privateGateway + " from " + _router); - _nicProfile = networkModel.getNicProfile(_router, privateNetwork.getId(), null); + _nicProfile = networkModel.getNicProfile(_router, privateNetwork.getId(), null, null); boolean result = visitor.visit(this); if (!result) { logger.warn("Failed to release private ip for gateway " + _privateGateway + " on router " + _router); diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java index bcf2c6176efe..9e14c70bd2c5 100644 --- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java @@ -42,8 +42,10 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.serializer.GsonHelper; import com.google.common.collect.Sets; +import com.google.gson.reflect.TypeToken; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.alert.AlertService; import org.apache.cloudstack.annotation.AnnotationService; @@ -69,6 +71,7 @@ import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.network.Ipv4GuestSubnetNetworkMap; import org.apache.cloudstack.network.RoutedIpv4Manager; @@ -395,7 +398,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { } createVpcOffering(VpcOffering.defaultVPCOfferingName, VpcOffering.defaultVPCOfferingName, svcProviderMap, true, State.Enabled, null, false, - false, false, null, null, false, false); + false, false, null, null, false, false, null, null); } // configure default vpc offering with Netscaler as LB Provider @@ -415,7 +418,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { } } createVpcOffering(VpcOffering.defaultVPCNSOfferingName, VpcOffering.defaultVPCNSOfferingName, - svcProviderMap, false, State.Enabled, null, false, false, false, null, null, false, false); + svcProviderMap, false, State.Enabled, null, false, false, false, null, null, false, false, null, null); } @@ -436,7 +439,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { } } createVpcOffering(VpcOffering.redundantVPCOfferingName, VpcOffering.redundantVPCOfferingName, svcProviderMap, true, State.Enabled, - null, false, false, true, null, null, false, false); + null, false, false, true, null, null, false, false, null, null); } // configure default vpc offering with NSX as network service provider in NAT mode @@ -453,7 +456,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { } } createVpcOffering(VpcOffering.DEFAULT_VPC_NAT_NSX_OFFERING_NAME, VpcOffering.DEFAULT_VPC_NAT_NSX_OFFERING_NAME, svcProviderMap, false, - State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.NATTED, null, false, false); + State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.NATTED, null, false, false, null, null); } @@ -471,7 +474,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { } } createVpcOffering(VpcOffering.DEFAULT_VPC_ROUTE_NSX_OFFERING_NAME, VpcOffering.DEFAULT_VPC_ROUTE_NSX_OFFERING_NAME, svcProviderMap, false, - State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.ROUTED, null, false, false); + State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.ROUTED, null, false, false, null, null); } @@ -489,7 +492,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { } } createVpcOffering(VpcOffering.DEFAULT_VPC_ROUTE_NETRIS_OFFERING_NAME, VpcOffering.DEFAULT_VPC_ROUTE_NETRIS_OFFERING_NAME, svcProviderMap, false, - State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.ROUTED, null, false, false); + State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.ROUTED, null, false, false, null, null); } @@ -507,7 +510,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { } } createVpcOffering(VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME, VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME, svcProviderMap, false, - State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.NATTED, null, false, false); + State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.NATTED, null, false, false, null, null); } } @@ -630,9 +633,23 @@ public VpcOffering createVpcOffering(CreateVPCOfferingCmd cmd) { throw new InvalidParameterValueException(msg); } + validateVpcOfferingMultiqueueParameters(cmd.getPublicMultiqueueNumber(), cmd.getPrivateGatewayMultiqueueNumber()); + return createVpcOffering(vpcOfferingName, displayText, supportedServices, serviceProviderList, serviceCapabilityList, internetProtocol, serviceOfferingId, provider, networkMode, - domainIds, zoneIds, (enable ? State.Enabled : State.Disabled), routingMode, specifyAsNumber, conserveMode); + domainIds, zoneIds, (enable ? State.Enabled : State.Disabled), routingMode, specifyAsNumber, conserveMode, + cmd.getPublicMultiqueueNumber(), cmd.getPrivateGatewayMultiqueueNumber()); + } + + private void validateVpcOfferingMultiqueueParameters(Integer publicMultiqueueNumber, Integer privateGatewayMultiqueueNumber) { + String errorMessage = "The only non-positive value accepted by the parameter [%s] is [-1]."; + if (publicMultiqueueNumber != null && publicMultiqueueNumber <= 0 && publicMultiqueueNumber != -1) { + throw new InvalidParameterValueException(String.format(errorMessage, ApiConstants.PUBLIC_MULTIQUEUE_NUMBER)); + } + + if (privateGatewayMultiqueueNumber != null && privateGatewayMultiqueueNumber <= 0 && privateGatewayMultiqueueNumber != -1) { + throw new InvalidParameterValueException(String.format(errorMessage, ApiConstants.PRIVATE_GATEWAY_MULTIQUEUE_NUMBER)); + } } @Override @@ -640,7 +657,7 @@ public VpcOffering createVpcOffering(CreateVPCOfferingCmd cmd) { public VpcOffering createVpcOffering(final String name, final String displayText, final List supportedServices, final Map> serviceProviders, final Map serviceCapabilityList, final NetUtils.InternetProtocol internetProtocol, final Long serviceOfferingId, final String externalProvider, final NetworkOffering.NetworkMode networkMode, List domainIds, List zoneIds, State state, - NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber, boolean conserveMode) { + NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber, boolean conserveMode, Integer publicMultiqueueNumber, Integer privateGatewayMultiqueueNumber) { boolean isExternalProvider = externalProvider != null && Arrays.asList("NSX", "Netris").stream().anyMatch(s -> s.equalsIgnoreCase(externalProvider)); @@ -741,7 +758,7 @@ public VpcOffering createVpcOffering(final String name, final String displayText final boolean offersRegionLevelVPC = isVpcOfferingForRegionLevelVpc(serviceCapabilityList); final boolean redundantRouter = isVpcOfferingRedundantRouter(serviceCapabilityList, redundantRouterService); final VpcOfferingVO offering = createVpcOffering(name, displayText, svcProviderMap, false, state, serviceOfferingId, supportsDistributedRouter, offersRegionLevelVPC, - redundantRouter, networkMode, routingMode, specifyAsNumber, conserveMode); + redundantRouter, networkMode, routingMode, specifyAsNumber, conserveMode, publicMultiqueueNumber, privateGatewayMultiqueueNumber); if (offering != null) { List detailsVO = new ArrayList<>(); @@ -769,13 +786,15 @@ public VpcOffering createVpcOffering(final String name, final String displayText @DB protected VpcOfferingVO createVpcOffering(final String name, final String displayText, final Map> svcProviderMap, final boolean isDefault, final State state, final Long serviceOfferingId, final boolean supportsDistributedRouter, final boolean offersRegionLevelVPC, - final boolean redundantRouter, NetworkOffering.NetworkMode networkMode, NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber, boolean conserveMode) { + final boolean redundantRouter, NetworkOffering.NetworkMode networkMode, NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber, + boolean conserveMode, Integer publicMultiqueueNumber, Integer privateGatewayMultiqueueNumber) { return Transaction.execute(new TransactionCallback() { @Override public VpcOfferingVO doInTransaction(final TransactionStatus status) { // create vpc offering object - VpcOfferingVO offering = new VpcOfferingVO(name, displayText, isDefault, serviceOfferingId, supportsDistributedRouter, offersRegionLevelVPC, redundantRouter); + VpcOfferingVO offering = new VpcOfferingVO(name, displayText, isDefault, serviceOfferingId, supportsDistributedRouter, offersRegionLevelVPC, + redundantRouter, publicMultiqueueNumber, privateGatewayMultiqueueNumber); if (state != null) { offering.setState(state); @@ -1041,6 +1060,12 @@ private void applyResolvedValuesToCommand(CloneVPCOfferingCmd cmd, VpcOfferingVO List sourceDomainIds, List sourceZoneIds, Map sourceServiceCapabilityList) { try { + Map requestPayload = new HashMap<>(); + if (cmd.getJob() instanceof AsyncJobVO) { + String asyncJobPayload = ((AsyncJobVO) cmd.getJob()).getCmdInfo(); + requestPayload = GsonHelper.getGson().fromJson(asyncJobPayload, new TypeToken>() {}.getType()); + } + if (cmd.getSupportedServices() == null || cmd.getSupportedServices().isEmpty()) { logger.debug("Setting supportedServices to {} services from source offering", finalServices.size()); ConfigurationManagerImpl.setField(cmd, "supportedServices", finalServices); @@ -1086,6 +1111,14 @@ private void applyResolvedValuesToCommand(CloneVPCOfferingCmd cmd, VpcOfferingVO } } + if (!requestPayload.containsKey(ApiConstants.PUBLIC_MULTIQUEUE_NUMBER) && sourceOffering.getPublicMultiqueueNumber() != null) { + ConfigurationManagerImpl.setField(cmd, "publicMultiqueueNumber", sourceOffering.getPublicMultiqueueNumber()); + } + + if (!requestPayload.containsKey(ApiConstants.PRIVATE_GATEWAY_MULTIQUEUE_NUMBER) && sourceOffering.getPrivateGatewayMultiqueueNumber() != null) { + ConfigurationManagerImpl.setField(cmd, "privateGatewayMultiqueueNumber", sourceOffering.getPrivateGatewayMultiqueueNumber()); + } + if (cmd.getNetworkMode() == null && sourceOffering.getNetworkMode() != null) { ConfigurationManagerImpl.setField(cmd, "networkMode", sourceOffering.getNetworkMode().toString()); } diff --git a/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java b/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java index 9a0b150780e4..0b49642957bd 100644 --- a/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java +++ b/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java @@ -465,6 +465,8 @@ public void testCreateNetworkOfferingForNsx() { when(createNetworkOfferingCmd.getTraffictype()).thenReturn(Networks.TrafficType.Guest.name()); when(createNetworkOfferingCmd.getGuestIpType()).thenReturn(Network.GuestType.Isolated.name()); when(createNetworkOfferingCmd.getAvailability()).thenReturn(NetworkOffering.Availability.Optional.name()); + when(createNetworkOfferingCmd.getPrivateMultiqueueNumber()).thenReturn(null); + when(createNetworkOfferingCmd.getPublicMultiqueueNumber()).thenReturn(null); when(configDao.getValue(anyString())).thenReturn("1000"); when(networkOfferingDao.persist(any(NetworkOfferingVO.class), anyMap())).thenReturn(offeringVO); doNothing().when(networkService).validateIfServiceOfferingIsActiveAndSystemVmTypeIsDomainRouter(anyLong()); diff --git a/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java b/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java index 3f2f3b6e955e..181c110e8a91 100644 --- a/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java +++ b/server/src/test/java/com/cloud/network/MockNetworkModelImpl.java @@ -798,13 +798,13 @@ public boolean isNetworkAvailableInDomain(long networkId, long domainId) { * @see com.cloud.network.NetworkModel#getNicProfile(com.cloud.vm.VirtualMachine, long, java.lang.String) */ @Override - public NicProfile getNicProfile(VirtualMachine vm, long networkId, String broadcastUri) { + public NicProfile getNicProfile(VirtualMachine vm, long networkId, String broadcastUri, Integer multiqueueNumber) { // TODO Auto-generated method stub return null; } @Override - public NicProfile getNicProfile(VirtualMachine vm, Nic nic, DataCenter dataCenter) { + public NicProfile getNicProfile(VirtualMachine vm, Nic nic, DataCenter dataCenter, Integer multiqueueNumber) { return null; } diff --git a/server/src/test/java/com/cloud/network/NetworkModelImplTest.java b/server/src/test/java/com/cloud/network/NetworkModelImplTest.java index 7810662c617b..2d48aaab45bf 100644 --- a/server/src/test/java/com/cloud/network/NetworkModelImplTest.java +++ b/server/src/test/java/com/cloud/network/NetworkModelImplTest.java @@ -294,7 +294,7 @@ public void getNicProfile_validInputs_returnsNicProfile() { doReturn(100).when(networkModel).getNetworkRate(1L, 10L); doReturn("cloud").when(networkModel).getNetworkTag(any(), any()); doReturn(false).when(networkModel).isSecurityGroupSupportedInNetwork(any()); - NicProfile result = networkModel.getNicProfile(vm, nic, mock(DataCenterVO.class)); + NicProfile result = networkModel.getNicProfile(vm, nic, mock(DataCenterVO.class), null); assertNotNull(result); } diff --git a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java index a8d3927f910e..14af9c74cf90 100644 --- a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -570,7 +570,7 @@ public NetworkOfferingVO createNetworkOffering(String name, String displayText, boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, Boolean forTungsten, boolean forNsx, boolean forNetris, NetworkOffering.NetworkMode networkMode, List domainIds, List zoneIds, boolean enableOffering, NetUtils.InternetProtocol internetProtocol, - NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber) { + NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber, Integer publicMultiqueueNumber, Integer privateMultiqueueNumber) { // TODO Auto-generated method stub return null; } diff --git a/server/src/test/java/com/cloud/vpc/MockNetworkModelImpl.java b/server/src/test/java/com/cloud/vpc/MockNetworkModelImpl.java index 83f3fda383c8..65daf2f054c9 100644 --- a/server/src/test/java/com/cloud/vpc/MockNetworkModelImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockNetworkModelImpl.java @@ -813,13 +813,13 @@ public boolean isNetworkAvailableInDomain(long networkId, long domainId) { * @see com.cloud.network.NetworkModel#getNicProfile(com.cloud.vm.VirtualMachine, long, java.lang.String) */ @Override - public NicProfile getNicProfile(VirtualMachine vm, long networkId, String broadcastUri) { + public NicProfile getNicProfile(VirtualMachine vm, long networkId, String broadcastUri, Integer multiqueueNumber) { // TODO Auto-generated method stub return null; } @Override - public NicProfile getNicProfile(VirtualMachine vm, Nic nic, DataCenter dataCenter) { + public NicProfile getNicProfile(VirtualMachine vm, Nic nic, DataCenter dataCenter, Integer multiqueueNumber) { return null; } diff --git a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java index f175c5674224..842d621c8b47 100644 --- a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java +++ b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java @@ -135,7 +135,7 @@ public void tearDown() { public void createSharedNtwkOffWithVlan() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false, null, false, null, true, false, false, false, false,null,null, null, false, null, null, false); + null, false, null, true, false, null, false, null, true, false, false, false, false,null,null, null, false, null, null, false, null, null); assertNotNull("Shared network offering with specifyVlan=true failed to create ", off); } @@ -143,7 +143,7 @@ public void createSharedNtwkOffWithVlan() { public void createSharedNtwkOffWithNoVlan() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, false, Availability.Optional, 200, null, false, Network.GuestType.Shared, - false, null, false, null, true, false, null, false, null, true, false, false, false, false,null, null,null, false, null, null, false); + false, null, false, null, true, false, null, false, null, true, false, false, false, false,null, null,null, false, null, null, false, null, null); assertNotNull("Shared network offering with specifyVlan=false was created", off); } @@ -151,7 +151,7 @@ public void createSharedNtwkOffWithNoVlan() { public void createSharedNtwkOffWithSpecifyIpRanges() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false, null, false, null, true, false, false, false, false,null,null, null, false, null, null, false); + null, false, null, true, false, null, false, null, true, false, false, false, false,null,null, null, false, null, null, false, null, null); assertNotNull("Shared network offering with specifyIpRanges=true failed to create ", off); } @@ -160,7 +160,7 @@ public void createSharedNtwkOffWithSpecifyIpRanges() { public void createSharedNtwkOffWithoutSpecifyIpRanges() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, - false, null, false, null, false, false, null, false, null, true, false, false, false,false, null,null, null, false, null, null, false); + false, null, false, null, false, false, null, false, null, true, false, false, false,false, null,null, null, false, null, null, false, null, null); assertNull("Shared network offering with specifyIpRanges=false was created", off); } @@ -173,7 +173,7 @@ public void createIsolatedNtwkOffWithNoVlan() { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, false, false, false,null, null, null, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, false, false, false,null, null, null, false, null, null, false, null, null); assertNotNull("Isolated network offering with specifyIpRanges=false failed to create ", off); } @@ -186,7 +186,7 @@ public void createIsolatedNtwkOffWithVlan() { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, false, false, false,null,null, null, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, false, false, false,null,null, null, false, null, null, false, null, null); assertNotNull("Isolated network offering with specifyVlan=true wasn't created", off); } @@ -199,7 +199,7 @@ public void createIsolatedNtwkOffWithSpecifyIpRangesAndSourceNat() { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, false, false, false,null,null, null, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, false, false, false,null,null, null, false, null, null, false, null, null); assertNull("Isolated network offering with specifyIpRanges=true and source nat service enabled, was created", off); } @@ -210,7 +210,7 @@ public void createIsolatedNtwkOffWithSpecifyIpRangesAndNoSourceNat() { Set vrProvider = new HashSet(); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, false, false, false,null,null, null, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, false, false, false,null,null, null, false, null, null, false, null, null); assertNotNull("Isolated network offering with specifyIpRanges=true and with no sourceNatService, failed to create", off); } @@ -228,7 +228,7 @@ public void createVpcNtwkOff() { serviceProviderMap.put(Network.Service.Lb, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false,null, null, null, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false,null, null, null, false, null, null, false, null, null); assertNotNull("Vpc Isolated network offering with Vpc provider ", off); } @@ -247,7 +247,7 @@ public void createVpcNtwkOffWithNetscaler() { serviceProviderMap.put(Network.Service.Lb, lbProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false,null, null, null, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false,null, null, null, false, null, null, false, null, null); assertNotNull("Vpc Isolated network offering with Vpc and Netscaler provider ", off); } } diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index f51f6f56126b..73cd74ccc59e 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -2079,6 +2079,8 @@ "label.privatemtu": "Private Interface MTU", "label.private.gateway": "Private Gateway", "label.private.interface": "Private interface", +"label.private.multiqueue.number": "Private NIC Multiqueue Number", +"label.private.gateway.multiqueue.number": "Private Gateway NIC Multiqueue Number", "label.private.registry": "Private registry", "label.privateinterface": "Private interface", "label.privateip": "Private IP address", @@ -2118,6 +2120,7 @@ "label.public.ip.addresses": "Public IP Addresses", "label.public.ips": "Public IP addresses", "label.public.lb": "Public LB", +"label.public.multiqueue.number": "Public NIC Multiqueue Number", "label.public.traffic": "Public traffic", "label.public.traffic.netris": "Netris Public IP Pool", "label.public.traffic.nsx": "NSX Public traffic", diff --git a/ui/public/locales/pt_BR.json b/ui/public/locales/pt_BR.json index 8fba779b1d12..34376377911d 100644 --- a/ui/public/locales/pt_BR.json +++ b/ui/public/locales/pt_BR.json @@ -1788,6 +1788,8 @@ "label.primarystoragetotal": "Armazenamento prim\u00e1rio", "label.private.gateway": "Gateway privado", "label.private.interface": "Interface privada", +"label.private.multiqueue.number": "N\u00famero de multiqueues da NIC privada", +"label.private.gateway.multiqueue.number": "N\u00famero de multiqueues da NIC de gateway privado", "label.private.registry": "Registro privado", "label.privateinterface": "Interface privada", "label.privateip": "Endere\u00e7o IP privado", @@ -1826,6 +1828,7 @@ "label.public.ip.addresses": "IPs P\u00fablicos", "label.public.ips": "IPs P\u00fablicos", "label.public.lb": "LB p\u00fablico", +"label.public.multiqueue.number": "N\u00famero de multiqueues da NIC p\u00fablica", "label.public.traffic": "Tr\u00e1fego p\u00fablico", "label.public.traffic.nsx": "Tr\u00e1fego P\u00fablico NSX", "label.publicipid": "ID do endere\u00e7o IP", diff --git a/ui/src/config/section/offering.js b/ui/src/config/section/offering.js index d8d06eb2ccb2..53ac20dbd764 100644 --- a/ui/src/config/section/offering.js +++ b/ui/src/config/section/offering.js @@ -447,7 +447,12 @@ export default { } return fields }, - details: ['name', 'id', 'displaytext', 'guestiptype', 'traffictype', 'internetprotocol', 'networkrate', 'ispersistent', 'egressdefaultpolicy', 'availability', 'conservemode', 'specifyvlan', 'routingmode', 'specifyasnumber', 'specifyipranges', 'supportspublicaccess', 'supportsstrechedl2subnet', 'forvpc', 'fornsx', 'networkmode', 'service', 'tags', 'domain', 'zone'], + details: [ + 'name', 'id', 'displaytext', 'guestiptype', 'traffictype', 'internetprotocol', 'networkrate', 'ispersistent', + 'egressdefaultpolicy', 'availability', 'conservemode', 'specifyvlan', 'routingmode', 'specifyasnumber', 'specifyipranges', + 'supportspublicaccess', 'supportsstrechedl2subnet', 'forvpc', 'fornsx', 'networkmode', { field: 'publicmultiqueuenumber', customTitle: 'public.multiqueue.number' }, + { field: 'privatemultiqueuenumber', customTitle: 'private.multiqueue.number' }, 'service', 'tags', 'domain', 'zone' + ], resourceType: 'NetworkOffering', customParamHandler: (params, query) => { const { filter } = query @@ -566,7 +571,11 @@ export default { searchFilters: ['name', 'zoneid', 'domainid'], resourceType: 'VpcOffering', columns: ['name', 'state', 'displaytext', 'domain', 'zone', 'order'], - details: ['name', 'id', 'displaytext', 'internetprotocol', 'distributedvpcrouter', 'tags', 'routingmode', 'specifyasnumber', 'service', 'fornsx', 'networkmode', 'conservemode', 'domain', 'zone', 'created'], + details: [ + 'name', 'id', 'displaytext', 'internetprotocol', 'distributedvpcrouter', { field: 'publicmultiqueuenumber', customTitle: 'public.multiqueue.number' }, + { field: 'privategatewaymultiqueuenumber', customTitle: 'private.gateway.multiqueue.number' }, 'tags', 'routingmode', + 'specifyasnumber', 'service', 'fornsx', 'networkmode', 'conservemode', 'domain', 'zone', 'created' + ], related: [{ name: 'vpc', title: 'label.vpc', diff --git a/ui/src/views/offering/AddNetworkOffering.vue b/ui/src/views/offering/AddNetworkOffering.vue index 4399bce91c42..dcf969a7e488 100644 --- a/ui/src/views/offering/AddNetworkOffering.vue +++ b/ui/src/views/offering/AddNetworkOffering.vue @@ -352,6 +352,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -375,7 +401,9 @@ export default { } return Promise.resolve() } - }] + }], + publicmultiqueuenumber: [{ type: 'number', validator: this.validateMultiqueueValue }], + privategatewaymultiqueuenumber: [{ type: 'number', validator: this.validateMultiqueueValue }] }) }, fetchData () { @@ -742,6 +770,8 @@ export default { if (values.enable) { params.enable = values.enable } + params.publicmultiqueuenumber = values.publicmultiqueuenumber + params.privategatewaymultiqueuenumber = values.privategatewaymultiqueuenumber postAPI('createVPCOffering', params).then(json => { this.$message.success(`${this.$t('message.create.vpc.offering')}: ` + values.name) this.$emit('refresh-data') @@ -755,6 +785,16 @@ export default { }, closeAction () { this.$emit('close-action') + }, + validateMultiqueueValue (rule, value) { + if (!value) { + return Promise.resolve() + } + const multiqueue = Number(value) + if (Number.isNaN(multiqueue) || (multiqueue <= 0 && multiqueue !== -1)) { + return Promise.reject(this.$t('message.error.number')) + } + return Promise.resolve() } } } diff --git a/ui/src/views/offering/CloneNetworkOffering.vue b/ui/src/views/offering/CloneNetworkOffering.vue index 0cd5e733b24f..cba011ae3131 100644 --- a/ui/src/views/offering/CloneNetworkOffering.vue +++ b/ui/src/views/offering/CloneNetworkOffering.vue @@ -356,6 +356,32 @@ + + + + + + + + + + + + + + { @@ -1409,6 +1446,16 @@ export default { }, closeAction () { this.$emit('close-action') + }, + validateMultiqueueValue (rule, value) { + if (!value) { + return Promise.resolve() + } + const multiqueue = Number(value) + if (Number.isNaN(multiqueue) || (multiqueue <= 0 && multiqueue !== -1)) { + return Promise.reject(this.$t('message.error.number')) + } + return Promise.resolve() } } } diff --git a/ui/src/views/offering/CloneVpcOffering.vue b/ui/src/views/offering/CloneVpcOffering.vue index 6adbfafad611..c65bd2b68762 100644 --- a/ui/src/views/offering/CloneVpcOffering.vue +++ b/ui/src/views/offering/CloneVpcOffering.vue @@ -212,6 +212,32 @@ + + + + + + + + + + + + + + @@ -397,7 +423,9 @@ export default { } return Promise.resolve() } - }] + }], + publicmultiqueuenumber: [{ type: 'number', validator: this.validateMultiqueueValue }], + privategatewaymultiqueuenumber: [{ type: 'number', validator: this.validateMultiqueueValue }] }) }, fetchData () { @@ -655,6 +683,14 @@ export default { if (this.provider === 'NSX') { this.form.nsxsupportlb = Boolean(this.serviceProviderMap.Lb) } + + if (r.publicmultiqueuenumber) { + this.form.publicmultiqueuenumber = r.publicmultiqueuenumber + } + + if (r.privategatewaymultiqueuenumber) { + this.form.privategatewaymultiqueuenumber = r.privategatewaymultiqueuenumber + } }, async handleProviderChange (value) { this.provider = value @@ -818,6 +854,9 @@ export default { params.enable = values.enable } + params.publicmultiqueuenumber = values.publicmultiqueuenumber + params.privategatewaymultiqueuenumber = values.privategatewaymultiqueuenumber + this.loading = true postAPI('cloneVPCOffering', params).then(json => { this.$message.success(`${this.$t('message.success.clone.vpc.offering')} ${values.name}`) @@ -834,6 +873,16 @@ export default { }, closeAction () { this.$emit('close-action') + }, + validateMultiqueueValue (rule, value) { + if (!value) { + return Promise.resolve() + } + const multiqueue = Number(value) + if (Number.isNaN(multiqueue) || (multiqueue <= 0 && multiqueue !== -1)) { + return Promise.reject(this.$t('message.error.number')) + } + return Promise.resolve() } } } From bcd79140b011bc0702adc731c4662668fee974e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernardo=20De=20Marco=20Gon=C3=A7alves?= Date: Fri, 9 Oct 2026 17:48:20 -0300 Subject: [PATCH 2/3] deny multi-queue values greater than 256 --- .../configuration/ConfigurationManagerImpl.java | 9 +++++++++ .../com/cloud/network/vpc/VpcManagerImpl.java | 16 +++++++++++++--- ui/src/views/offering/AddNetworkOffering.vue | 2 +- ui/src/views/offering/AddVpcOffering.vue | 2 +- ui/src/views/offering/CloneNetworkOffering.vue | 2 +- ui/src/views/offering/CloneVpcOffering.vue | 2 +- 6 files changed, 26 insertions(+), 7 deletions(-) diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 37e7ee77ac1c..46cca5f6f10b 100644 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -7480,6 +7480,7 @@ private void validateNetworkOfferingMultiqueueParameters(Integer publicMultiqueu throw new InvalidParameterValueException("Multiqueue parameters cannot be specified for L2 network offerings."); } + String multiqueueGreaterThanMaximumErrorMessage = "[%s] parameter cannot be greater than 256."; if (publicMultiqueueNumber != null) { if (forVpc) { throw new InvalidParameterValueException(String.format("The [%s] parameter cannot be specified for offerings that are meant to be used for VPC tiers.", ApiConstants.PUBLIC_MULTIQUEUE_NUMBER)); @@ -7488,11 +7489,19 @@ private void validateNetworkOfferingMultiqueueParameters(Integer publicMultiqueu if (publicMultiqueueNumber <= 0 && publicMultiqueueNumber != -1) { throw new InvalidParameterValueException(String.format("The only non-positive value accepted by the parameter [%s] is [-1].", ApiConstants.PUBLIC_MULTIQUEUE_NUMBER)); } + + if (publicMultiqueueNumber > 256) { + throw new InvalidParameterValueException(String.format(multiqueueGreaterThanMaximumErrorMessage, ApiConstants.PUBLIC_MULTIQUEUE_NUMBER)); + } } if (privateMultiqueueNumber != null && privateMultiqueueNumber <= 0 && privateMultiqueueNumber != -1) { throw new InvalidParameterValueException(String.format("The only non-positive value accepted by the parameter [%s] is [-1].", ApiConstants.PRIVATE_MULTIQUEUE_NUMBER)); } + + if (privateMultiqueueNumber != null && privateMultiqueueNumber > 256) { + throw new InvalidParameterValueException(String.format(multiqueueGreaterThanMaximumErrorMessage, ApiConstants.PRIVATE_MULTIQUEUE_NUMBER)); + } } public static NetworkOffering.RoutingMode verifyRoutingMode(String routingModeString) { diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java index 9e14c70bd2c5..78ad8685ae1d 100644 --- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java @@ -642,13 +642,23 @@ public VpcOffering createVpcOffering(CreateVPCOfferingCmd cmd) { } private void validateVpcOfferingMultiqueueParameters(Integer publicMultiqueueNumber, Integer privateGatewayMultiqueueNumber) { - String errorMessage = "The only non-positive value accepted by the parameter [%s] is [-1]."; + String nonPositiveMultiqueueErrorMessage = "The only non-positive value accepted by the parameter [%s] is [-1]."; + String multiqueueGreaterThanMaximumErrorMessage = "[%s] parameter cannot be greater than 256."; + if (publicMultiqueueNumber != null && publicMultiqueueNumber <= 0 && publicMultiqueueNumber != -1) { - throw new InvalidParameterValueException(String.format(errorMessage, ApiConstants.PUBLIC_MULTIQUEUE_NUMBER)); + throw new InvalidParameterValueException(String.format(nonPositiveMultiqueueErrorMessage, ApiConstants.PUBLIC_MULTIQUEUE_NUMBER)); + } + + if (publicMultiqueueNumber != null && publicMultiqueueNumber > 256) { + throw new InvalidParameterValueException(String.format(multiqueueGreaterThanMaximumErrorMessage, ApiConstants.PUBLIC_MULTIQUEUE_NUMBER)); } if (privateGatewayMultiqueueNumber != null && privateGatewayMultiqueueNumber <= 0 && privateGatewayMultiqueueNumber != -1) { - throw new InvalidParameterValueException(String.format(errorMessage, ApiConstants.PRIVATE_GATEWAY_MULTIQUEUE_NUMBER)); + throw new InvalidParameterValueException(String.format(nonPositiveMultiqueueErrorMessage, ApiConstants.PRIVATE_GATEWAY_MULTIQUEUE_NUMBER)); + } + + if (privateGatewayMultiqueueNumber != null && privateGatewayMultiqueueNumber > 256) { + throw new InvalidParameterValueException(String.format(multiqueueGreaterThanMaximumErrorMessage, ApiConstants.PRIVATE_GATEWAY_MULTIQUEUE_NUMBER)); } } diff --git a/ui/src/views/offering/AddNetworkOffering.vue b/ui/src/views/offering/AddNetworkOffering.vue index dcf969a7e488..adf9971eafe2 100644 --- a/ui/src/views/offering/AddNetworkOffering.vue +++ b/ui/src/views/offering/AddNetworkOffering.vue @@ -1302,7 +1302,7 @@ export default { return Promise.resolve() } const multiqueue = Number(value) - if (Number.isNaN(multiqueue) || (multiqueue <= 0 && multiqueue !== -1)) { + if (Number.isNaN(multiqueue) || (multiqueue <= 0 && multiqueue !== -1) || multiqueue > 256) { return Promise.reject(this.$t('message.error.number')) } return Promise.resolve() diff --git a/ui/src/views/offering/AddVpcOffering.vue b/ui/src/views/offering/AddVpcOffering.vue index 4a183e8e71a7..697cc0d55e2d 100644 --- a/ui/src/views/offering/AddVpcOffering.vue +++ b/ui/src/views/offering/AddVpcOffering.vue @@ -791,7 +791,7 @@ export default { return Promise.resolve() } const multiqueue = Number(value) - if (Number.isNaN(multiqueue) || (multiqueue <= 0 && multiqueue !== -1)) { + if (Number.isNaN(multiqueue) || (multiqueue <= 0 && multiqueue !== -1) || multiqueue > 256) { return Promise.reject(this.$t('message.error.number')) } return Promise.resolve() diff --git a/ui/src/views/offering/CloneNetworkOffering.vue b/ui/src/views/offering/CloneNetworkOffering.vue index cba011ae3131..9f7855e5f16f 100644 --- a/ui/src/views/offering/CloneNetworkOffering.vue +++ b/ui/src/views/offering/CloneNetworkOffering.vue @@ -1452,7 +1452,7 @@ export default { return Promise.resolve() } const multiqueue = Number(value) - if (Number.isNaN(multiqueue) || (multiqueue <= 0 && multiqueue !== -1)) { + if (Number.isNaN(multiqueue) || (multiqueue <= 0 && multiqueue !== -1) || multiqueue > 256) { return Promise.reject(this.$t('message.error.number')) } return Promise.resolve() diff --git a/ui/src/views/offering/CloneVpcOffering.vue b/ui/src/views/offering/CloneVpcOffering.vue index c65bd2b68762..cdbdc4fd6115 100644 --- a/ui/src/views/offering/CloneVpcOffering.vue +++ b/ui/src/views/offering/CloneVpcOffering.vue @@ -879,7 +879,7 @@ export default { return Promise.resolve() } const multiqueue = Number(value) - if (Number.isNaN(multiqueue) || (multiqueue <= 0 && multiqueue !== -1)) { + if (Number.isNaN(multiqueue) || (multiqueue <= 0 && multiqueue !== -1) || multiqueue > 256) { return Promise.reject(this.$t('message.error.number')) } return Promise.resolve() From 7792239e2647bd0d4418fe1d99fb6497777c5d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernardo=20De=20Marco=20Gon=C3=A7alves?= Date: Fri, 9 Oct 2026 17:55:13 -0300 Subject: [PATCH 3/3] add guard to avoid setting multi-queue to -1 --- .../cloud/hypervisor/kvm/resource/LibvirtComputingResource.java | 2 ++ 1 file changed, 2 insertions(+) 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 eb020246f3fb..c952d3095c40 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 @@ -6868,6 +6868,8 @@ public void setInterfaceDefQueueSettings(Map details, Integer cp if (nicMultiqueueNumber == InterfaceDef.MULTI_QUEUE_NUMBER_MEANS_CPU_CORES && cpus != null && cpus > 0) { logger.info("The NIC multiqueue number is equal to [{}]. Thus, defining the multiqueue value as the number of vCPUs [{}].", InterfaceDef.MULTI_QUEUE_NUMBER_MEANS_CPU_CORES, cpus); interfaceDef.setMultiQueueNumber(cpus); + } else if (nicMultiqueueNumber == InterfaceDef.MULTI_QUEUE_NUMBER_MEANS_CPU_CORES) { + logger.info("Not setting NIC multiqueue number, as it is equal to [{}] and there is not associated number of vCPUs to be considered.", InterfaceDef.MULTI_QUEUE_NUMBER_MEANS_CPU_CORES); } else { logger.debug("Defining the NIC multiqueue number as [{}] in the NIC XML definition.", nicMultiqueueNumber); interfaceDef.setMultiQueueNumber(nicMultiqueueNumber);