Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
e45ea95
engine-schema: upgrade path for 24.0.0
shwstppr Sep 14, 2026
c2ebb3a
Support multi-VLAN trunk NICs
Pearl1594 Sep 14, 2026
219f9cb
Merge branch 'main' of github.com:apache/cloudstack into support-mult…
Pearl1594 Sep 14, 2026
eb97acf
deliver multi-VLAN trunk nics via libvirt vlan XML and bridge fallback
Pearl1594 Sep 16, 2026
d143862
Fix nic_network_map unique constraint blocking re-association
Pearl1594 Sep 28, 2026
a7b6a8e
Deliver multi-VLAN trunk NICs on KVM via libvirt vlan XML and bridge …
Pearl1594 Sep 28, 2026
bcb89ab
Bill usage for a trunk nic's associated networks
Pearl1594 Sep 28, 2026
3d27d89
Expose trunk nic and associated-network info in NicResponse
Pearl1594 Sep 28, 2026
dd4ee2a
Add ApiConstants for NicResponse trunk fields
Pearl1594 Sep 28, 2026
c16a58d
Add multi-VLAN trunk NIC association service
Pearl1594 Sep 28, 2026
88585ed
Add EventTypes constants for the association service commit
Pearl1594 Sep 28, 2026
df74bd9
Support multi-VLAN trunk NICs at VM deploy time
Pearl1594 Sep 28, 2026
3a7519d
Fix static NAT lookup in disassociate guard
Pearl1594 Sep 28, 2026
68d7771
Fix VNF management nic trunkable via live associate API
Pearl1594 Sep 28, 2026
485ad26
Fix stale nic fields after changing its primary network
Pearl1594 Sep 28, 2026
721bae1
Clear multiNetwork flag when a nic's last trunk association is removed
Pearl1594 Sep 29, 2026
1a3ddfb
Push DHCP entries to a trunk nic's associated networks
Pearl1594 Sep 29, 2026
5088e0b
Add KVM live migration support for multi-VLAN trunk NICs (Phase 7)
Pearl1594 Oct 2, 2026
01729b9
Merge branch 'main' of github.com:apache/cloudstack into support-mult…
Pearl1594 Oct 2, 2026
c9b98ea
fix test
Pearl1594 Oct 2, 2026
5f95946
Fix CI build failures from the multi-VLAN trunk NIC changes
Pearl1594 Oct 2, 2026
b4c18d6
Fix NullPointerException in LibvirtComputingResourceTest.testMigrateC…
Pearl1594 Oct 2, 2026
749b2b7
Fix DHCP databag merge clobbering a trunk nic's sibling entry on shar…
Pearl1594 Oct 6, 2026
0988ace
Usage: Fix usage_network_offering row mismatches on nic removal and d…
Pearl1594 Oct 7, 2026
fb2e91f
Finish VM deploy/VNF UI, migration host-readiness, and trunk-associat…
Pearl1594 Oct 7, 2026
3fafc1e
Allow trunk nic associations across VPCs; fix network selection reset…
Pearl1594 Oct 7, 2026
6da1e9a
Carry trunk nic associations across assignVirtualMachine account moves
Pearl1594 Oct 7, 2026
e021624
Merge branch 'main' of github.com:apache/cloudstack into support-mult…
Pearl1594 Oct 13, 2026
a0f47df
Increase test coverage
Pearl1594 Oct 13, 2026
1e2048b
Fix associated network state corruption from reaper race; defer imple…
Pearl1594 Oct 15, 2026
aa203a4
Merge branch 'main' of github.com:apache/cloudstack into support-mult…
Pearl1594 Oct 15, 2026
0dcc9be
Remove stray default VLAN 1 membership when plugging VLAN nics on lib…
Pearl1594 Oct 19, 2026
0cc7d58
add 'nic' object name to the responses for trunk nics
Pearl1594 Oct 19, 2026
3fc9b84
remove usage of internal db ids
Pearl1594 Oct 19, 2026
da31dd6
Rollback IP allocation on trunk nic network association failure
Pearl1594 Oct 20, 2026
a39ef01
in case of insufficient IPs fail association rather than persist with…
Pearl1594 Oct 21, 2026
017cebf
Allocate and release trunk nic associated-network IPs via user_ip_add…
Pearl1594 Oct 21, 2026
133f9c3
Added a new detail (host) guest.bridge.stp.enabled to get the stp sta…
Pearl1594 Oct 21, 2026
767d0ea
Fix DHCP removal replay deleting a trunk nic's live entry after chang…
Pearl1594 Oct 21, 2026
1214977
Expunge orphaned Instance when nicnetworkslist association fails afte…
Pearl1594 Oct 21, 2026
a44771c
Clear nic-vlan-mapping metadata file instead of skipping it when expo…
Pearl1594 Oct 21, 2026
2ac6937
Warn when a live trunk VLAN association leaves the uplink missing tha…
Pearl1594 Oct 21, 2026
a15a3ab
Reject assignVirtualMachine with plain networkids when VM has trunk n…
Pearl1594 Oct 21, 2026
d26bec7
Reject nicnetworkslist on deployVirtualMachine for non-root-admin cal…
Pearl1594 Oct 21, 2026
4b23ed3
Resolve trunk nic readiness/STP checks against the Guest traffic labe…
Pearl1594 Oct 22, 2026
4b10409
Derive trunk association's IPv6 via EUI-64 for every guest type, not …
Pearl1594 Oct 22, 2026
e937ecd
Merge branch 'main' of github.com:apache/cloudstack into support-mult…
Pearl1594 Oct 22, 2026
6396f99
Reject unmanaging a VM with trunk nic associations
Pearl1594 Oct 22, 2026
fe7b458
Reject migrateVirtualMachineWithVolume to a host without VLAN filteri…
Pearl1594 Oct 22, 2026
c34a330
fix: alert when post-migration tasks fail on KVM destination
Pearl1594 Oct 22, 2026
5a4eca5
fix: serialize nic trunk network association to prevent duplicate rows
Pearl1594 Oct 22, 2026
d6444aa
fix: check caller access to a requested network before its state
Pearl1594 Oct 22, 2026
ae00248
test: assert access is checked before already-associated state leaks
Pearl1594 Oct 22, 2026
93edba4
fix: check vm owner's network permissions, not caller's, in trunk ass…
Pearl1594 Oct 22, 2026
47dc241
fix: check trunk nic association before network delete/GC regardless …
Pearl1594 Oct 22, 2026
a1fc612
fix: serialize trunk nic association against concurrent network delete
Pearl1594 Oct 22, 2026
d06302b
fix: serialize trunk nic mutations and re-read nic state under lock
Pearl1594 Oct 22, 2026
0d05ae6
fix: scope trunk nic's associatednetworks to the requested network in…
Pearl1594 Oct 22, 2026
6eaa656
fix: reject duplicate network ids in associateNetworkToNic
Pearl1594 Oct 23, 2026
d4a1b34
fix: serialize trunk nic disassociation against concurrent network de…
Pearl1594 Oct 23, 2026
35d0e84
fix IP not released on VM is expuged
Pearl1594 Oct 23, 2026
37c1802
fix: restore tap VLAN membership when a partial live trunk update fai…
Pearl1594 Oct 23, 2026
2b950ce
remove printing network int db id
Pearl1594 Oct 23, 2026
df4f944
fix: restrict nicnetworkslist on assignVirtualMachine to root admin
Pearl1594 Oct 23, 2026
ac056e3
fix: refresh guest bridge STP host detail after the guest traffic lab…
Pearl1594 Oct 23, 2026
275739c
fix: refuse changecidr while running VMs carry the network as a trunk…
Pearl1594 Oct 23, 2026
1f57bfc
fix: roll back earlier nic network associations when a later network …
Pearl1594 Oct 23, 2026
31747c6
fix: apply listVirtualMachines filters and paging to VMs associated w…
Pearl1594 Oct 23, 2026
628acb6
fix: reapply trunk nic vlan membership after memory vm snapshot rever…
Pearl1594 Oct 23, 2026
238268e
keep vlan membership when updateVmNic toggles a nic link on shared-br…
Pearl1594 Oct 23, 2026
4da5674
fix: expose nic-vlan-mapping on the first network association to a ru…
Pearl1594 Oct 23, 2026
4ddf474
fix: keep trunk nic associations and refresh live vlan membership whe…
Pearl1594 Oct 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions api/src/main/java/com/cloud/agent/api/to/NicTO.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ public class NicTO extends NetworkTO {

String networkSegmentName;

boolean trunkVlan;
List<NetworkTO> associatedNetworks;

public NicTO() {
super();
}
Expand Down Expand Up @@ -163,4 +166,21 @@ public boolean isEnabled() {
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}

// trunkVlan/associatedNetworks carry the additional networks for a multi-VLAN trunk nic; unset for ordinary nics
public boolean isTrunkVlan() {
return trunkVlan;
}

public void setTrunkVlan(boolean trunkVlan) {
this.trunkVlan = trunkVlan;
}

public List<NetworkTO> getAssociatedNetworks() {
return associatedNetworks;
}

public void setAssociatedNetworks(List<NetworkTO> associatedNetworks) {
this.associatedNetworks = associatedNetworks;
}
}
8 changes: 8 additions & 0 deletions api/src/main/java/com/cloud/event/EventTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,11 @@ public class EventTypes {
public static final String EVENT_NIC_DETAIL_ADD = "NIC.DETAIL.ADD";
public static final String EVENT_NIC_DETAIL_UPDATE = "NIC.DETAIL.UPDATE";
public static final String EVENT_NIC_DETAIL_REMOVE = "NIC.DETAIL.REMOVE";
public static final String EVENT_NIC_NETWORK_ASSOCIATE = "NIC.NETWORK.ASSOCIATE";
public static final String EVENT_NIC_NETWORK_DISASSOCIATE = "NIC.NETWORK.DISASSOCIATE";
public static final String EVENT_NIC_PRIMARY_NETWORK_CHANGE = "NIC.PRIMARY.NETWORK.CHANGE";
// internal-only signal consumed by the usage job - never user-facing, not an audit event
public static final String EVENT_NIC_NETWORK_ID_BACKFILL = "NIC.NETWORK.ID.BACKFILL";

// Load Balancers
public static final String EVENT_ASSIGN_TO_LOAD_BALANCER_RULE = "LB.ASSIGN.TO.RULE";
Expand Down Expand Up @@ -1000,6 +1005,9 @@ public class EventTypes {

// Nic Events
entityEventDetails.put(EVENT_NIC_CREATE, Nic.class);
entityEventDetails.put(EVENT_NIC_NETWORK_ASSOCIATE, Nic.class);
entityEventDetails.put(EVENT_NIC_NETWORK_DISASSOCIATE, Nic.class);
entityEventDetails.put(EVENT_NIC_PRIMARY_NETWORK_CHANGE, Nic.class);

// Load Balancers
entityEventDetails.put(EVENT_ASSIGN_TO_LOAD_BALANCER_RULE, FirewallRule.class);
Expand Down
3 changes: 3 additions & 0 deletions api/src/main/java/com/cloud/host/Host.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ public static String[] toStrings(Host.Type... types) {
String HOST_QEMU_RBD_SUPPORT = "host.qemu.rbd.support";
String HOST_SSH_PORT = "host.ssh.port";
String HOST_CDROM_MAX_COUNT = "host.cdrom.max.count";
String HOST_VLAN_FILTERING_ENABLED = "vlan.filtering.enabled";
String HOST_VLAN_TRUNK_XML_SUPPORTED = "vlan.trunk.xml.supported";
String HOST_GUEST_BRIDGE_STP_ENABLED = "guest.bridge.stp.enabled";
String GUEST_OS_CATEGORY_ID = "guest.os.category.id";
String GUEST_OS_RULE = "guest.os.rule";

Expand Down
8 changes: 8 additions & 0 deletions api/src/main/java/com/cloud/network/NetworkModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public interface NetworkModel {
String CLOUD_DOMAIN_FILE = "cloud-domain";
String CLOUD_DOMAIN_ID_FILE = "cloud-domain-id";
String CLOUD_NAME_FILE = "cloud-name";
String NIC_VLAN_MAPPING_FILE = "nic-vlan-mapping";
int CONFIGDATA_DIR = 0;
int CONFIGDATA_FILE = 1;
int CONFIGDATA_CONTENT = 2;
Expand Down Expand Up @@ -137,6 +138,13 @@ public interface NetworkModel {

Nic getNicInNetwork(long vmId, long networkId);

/**
* Resolves the nic and guest ip(s) a VM answers on for a given network - the nic's own primary network match
* when one exists, or a trunk nic's association (from nic_network_map) otherwise. Returns null if the VM has
* neither a primary nor an associated nic in that network.
*/
Pair<Nic, Network.IpAddresses> getNicAndIpInNetwork(long vmId, long networkId);

List<? extends Nic> getNicsForTraffic(long vmId, TrafficType type);

Network getDefaultNetworkForVm(long vmId);
Expand Down
36 changes: 36 additions & 0 deletions api/src/main/java/com/cloud/network/NetworkService.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
import org.apache.cloudstack.api.command.user.network.ResetNetworkPermissionsCmd;
import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd;
import org.apache.cloudstack.api.command.user.network.UpdateNetworkCmd;
import org.apache.cloudstack.api.command.admin.network.AssociateNetworkToNicCmd;
import org.apache.cloudstack.api.command.admin.network.ChangeNicPrimaryNetworkCmd;
import org.apache.cloudstack.api.command.admin.network.DisassociateNetworkFromNicCmd;
import org.apache.cloudstack.api.command.user.vm.ListNicsCmd;
import org.apache.cloudstack.api.response.AcquirePodIpCmdResponse;
import org.apache.cloudstack.framework.config.ConfigKey;
Expand All @@ -59,6 +62,7 @@
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.Nic;
import com.cloud.vm.NicSecondaryIp;
import com.cloud.vm.VirtualMachine;

/**
* The NetworkService interface is the "public" api to entities that make requests to the orchestration engine
Expand Down Expand Up @@ -249,6 +253,32 @@ Network createPrivateNetwork(String networkName, String displayText, long physic

List<? extends NicSecondaryIp> listVmNicSecondaryIps(ListNicsCmd listNicsCmd);

/**
* Associates one or more additional networks with an existing nic, delivering them as a multi-VLAN trunk
*/
Nic associateNetworkToNic(AssociateNetworkToNicCmd cmd)
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, InsufficientAddressCapacityException;

/**
* Disassociates a network from an existing nic, shrinking its multi-VLAN trunk. The primary network cannot be disassociated.
*/
Nic disassociateNetworkFromNic(DisassociateNetworkFromNicCmd cmd) throws ResourceUnavailableException;

/**
* Changes a multi-VLAN trunk nic's primary network to one of its already-associated networks. Only allowed while
* the owning Instance is stopped, since the nic is rebuilt fresh on its next start.
*/
Nic changeNicPrimaryNetwork(ChangeNicPrimaryNetworkCmd cmd);

/**
* Associates additional networks with a nic that was just created (e.g. during VM deploy), before the owning
* Instance has ever started. No live agent update is issued - the nic's first plug already reads these
* associations fresh. requestedIps (nullable) optionally requests a specific ip4/ip6 address per associated
* network id - a network with no entry (or a null map) auto-allocates, same as today.
*/
void associateNetworksToNic(Nic nic, List<Long> networkIds, Map<Long, IpAddresses> requestedIps)
throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, InsufficientAddressCapacityException;

AcquirePodIpCmdResponse allocatePodIp(Account account, String zoneId, String podId) throws ResourceAllocationException, ConcurrentOperationException;

boolean releasePodIp(ReleasePodIpCmdByAdmin ip) throws CloudRuntimeException;
Expand Down Expand Up @@ -281,4 +311,10 @@ Network createPrivateNetwork(String networkName, String displayText, long physic
String getNicVlanValueForExternalVm(NicTO nic);

Long getPreferredNetworkIdForPublicIpRuleAssignment(IpAddress ip, Long networkId);

// Re-applies each nic's VLAN membership on the host of a Running Instance, e.g. after a memory revert recreates its taps.
void reapplyLiveVlanMembership(VirtualMachine vm) throws ResourceUnavailableException;

// Pushes a migrated network's new VLAN and DHCP entries to the Running Instances that carry it as a trunk nic association.
void refreshTrunkNicsAssociatedToNetwork(Network network);
}
14 changes: 14 additions & 0 deletions api/src/main/java/com/cloud/server/ManagementService.java
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,20 @@ public interface ManagementService {

Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> listHostsForMigrationOfVM(VirtualMachine vm, Long startIndex, Long pageSize, String keyword, List<VirtualMachine> vmList);

/**
* If vm has a multi-VLAN trunk NIC and host is not ready for it (VLAN filtering not enabled), returns a
* human-readable reason; null otherwise (including when vm has no such NIC, in which case host readiness
* for this concern is irrelevant).
*/
String getMultiNetworkNicUnsuitableReason(VirtualMachine vm, Host host);

/**
* If host's guest bridge has STP enabled, returns a human-readable caution about the forward-delay outage
* every new port on it incurs (migration, nic plug, vm start); null otherwise. Applies to every VM, not
* just ones with a multi-VLAN trunk NIC - unlike getMultiNetworkNicUnsuitableReason, never excludes the host.
*/
String getGuestBridgeStpMigrationCaution(Host host);

/**
* Apply affinity group constraints and other exclusion rules for VM migration.
* This is a helper method that can be used independently for per-iteration affinity checks in DRS.
Expand Down
2 changes: 2 additions & 0 deletions api/src/main/java/com/cloud/vm/Nic.java
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ public enum ReservationStrategy {

boolean getSecondaryIp();

boolean getMultiNetwork();

//
// IPv4
//
Expand Down
5 changes: 5 additions & 0 deletions api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ public class ApiConstants {
public static final String MOVE_ACL_CONSISTENCY_HASH = "aclconsistencyhash";
public static final String IMAGE_PATH = "imagepath";
public static final String INSTANCE_CONVERSION_SUPPORTED = "instanceconversionsupported";
public static final String VLAN_FILTERING_ENABLED = "vlanfilteringenabled";
public static final String VLAN_TRUNK_XML_SUPPORTED = "vlantrunkxmlsupported";
public static final String INTERNAL_DNS1 = "internaldns1";
public static final String INTERNAL_DNS2 = "internaldns2";
public static final String INTERNET_PROTOCOL = "internetprotocol";
Expand Down Expand Up @@ -438,6 +440,7 @@ public class ApiConstants {
public static final String NIC = "nic";
public static final String NICS = "nics";
public static final String NIC_NETWORK_LIST = "nicnetworklist";
public static final String NIC_NETWORKS_LIST = "nicnetworkslist";
public static final String NIC_IP_ADDRESS_LIST = "nicipaddresslist";
public static final String NIC_MULTIQUEUE_NUMBER = "nicmultiqueuenumber";
public static final String NIC_PACKED_VIRTQUEUES_ENABLED = "nicpackedvirtqueuesenabled";
Expand Down Expand Up @@ -906,6 +909,8 @@ public class ApiConstants {
public static final String ASSOCIATED_NETWORK = "associatednetwork";
public static final String ASSOCIATED_NETWORK_ID = "associatednetworkid";
public static final String ASSOCIATED_NETWORK_NAME = "associatednetworkname";
public static final String ASSOCIATED_NETWORKS = "associatednetworks";
public static final String TRUNKED = "trunked";
public static final String ASSOCIATED_VPC_ID = "associatedvpcid";
public static final String ASSOCIATED_VPC_NAME = "associatedvpcname";
public static final String SOURCE_NAT_SUPPORTED = "sourcenatsupported";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,8 @@ UsageRecordResponse createUsageResponse(Usage usageRecord,

public NicResponse createNicResponse(Nic result);

public NicResponse createNicResponse(Nic result, Long networkId);

ApplicationLoadBalancerResponse createLoadBalancerContainerReponse(ApplicationLoadBalancerRule lb,
Map<Ip, UserVm> lbInstances);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.cloud.host.Host;
import com.cloud.utils.Pair;
import com.cloud.utils.Ternary;
import com.cloud.vm.VirtualMachine;

@APICommand(name = "findHostsForMigration", description = "Find hosts suitable for migrating an Instance.", responseObject = HostForMigrationResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
Expand Down Expand Up @@ -73,6 +74,8 @@ public void execute() {
List<? extends Host> hostsWithCapacity = hostsForMigration.second();
hostsRequiringStorageMotion = hostsForMigration.third();

VirtualMachine vm = _entityMgr.findById(VirtualMachine.class, getVirtualMachineId());

response = new ListResponse<HostForMigrationResponse>();
List<HostForMigrationResponse> hostResponses = new ArrayList<HostForMigrationResponse>();
for (Host host : result.first()) {
Expand All @@ -90,6 +93,11 @@ public void execute() {
hostResponse.setRequiresStorageMotion(false);
}

if (!suitableForMigration && vm != null) {
hostResponse.setUnsuitableReason(_mgr.getMultiNetworkNicUnsuitableReason(vm, host));
}
hostResponse.setMigrationCaution(_mgr.getGuestBridgeStpMigrationCaution(host));

hostResponse.setObjectName("host");
hostResponses.add(hostResponse);
}
Expand Down
Loading
Loading