From 24a03834dca0eccaba2f83e212fa646010f0af5e Mon Sep 17 00:00:00 2001 From: abh1sar Date: Mon, 25 Aug 2025 17:17:05 +0530 Subject: [PATCH 1/7] Get vlan from bridge name while importing kvm instances --- .../kvm/resource/LibvirtDomainXMLParser.java | 24 +++++++++++++++++++ .../compute/wizard/MultiNetworkSelection.vue | 14 ++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java index c4d5ac48f6f8..6ad7a7ccbb09 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java @@ -241,6 +241,12 @@ public boolean parseDomainXML(String domXML) { } else if (type.equalsIgnoreCase("bridge")) { String bridge = getAttrValue("source", "bridge", nic); def.defBridgeNet(bridge, dev, mac, NicModel.valueOf(model.toUpperCase()), networkRateKBps); + if (StringUtils.isNotBlank(bridge)) { + Integer vlanId = extractVlanFromBridgeName(bridge); + if (vlanId != null) { + def.setVlanTag(vlanId); + } + } } else if (type.equalsIgnoreCase("ethernet")) { String scriptPath = getAttrValue("script", "path", nic); def.defEthernet(dev, mac, NicModel.valueOf(model.toUpperCase()), scriptPath, networkRateKBps); @@ -569,4 +575,22 @@ private void extractCpuModeDef(final Element rootElement){ } } } + + private Integer extractVlanFromBridgeName(String bridge) { + if (!bridge.startsWith("br")) { + return null; + } + String[] splitByDash = bridge.split("-"); + if (splitByDash.length < 2) { + return null; + } + try { + Integer vlanId = Integer.parseInt(splitByDash[splitByDash.length - 1]); + if (vlanId >=1 && vlanId <= 4094) { + return vlanId; + } + } catch (NumberFormatException e) { + } + return null; + } } diff --git a/ui/src/views/compute/wizard/MultiNetworkSelection.vue b/ui/src/views/compute/wizard/MultiNetworkSelection.vue index 92d4a4375994..4d11aba118aa 100644 --- a/ui/src/views/compute/wizard/MultiNetworkSelection.vue +++ b/ui/src/views/compute/wizard/MultiNetworkSelection.vue @@ -47,7 +47,7 @@ Number(x.vlan) === record.vlanid) + console.log('matched', matched) + if (matched.length > 0) { + this.handleNetworkChange(record, matched[0].id) + return matched[0].id + } + } + return this.validNetworks[record.id][0].id + }, sendValuesTimed () { clearTimeout(this.sendValuesTimer) this.sendValuesTimer = setTimeout(() => { From 5d2e6649e148777ee759d9098c3ee1ae5bb8460c Mon Sep 17 00:00:00 2001 From: abh1sar Date: Mon, 25 Aug 2025 18:11:35 +0530 Subject: [PATCH 2/7] Fix LibvirtReplugNicCommandWrapperTest --- .../resource/wrapper/LibvirtReplugNicCommandWrapperTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapperTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapperTest.java index 8a6827f4139c..b083959094bd 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapperTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapperTest.java @@ -252,6 +252,9 @@ public void testReplugNic() throws LibvirtException { + "\n" + "\n" + "\n" + + "\n" + + "\n" + + "" + "\n" + "\n"; final String expectedAttachXml = From bb066cd815bbea833543ff136b6ec6583cee3fe4 Mon Sep 17 00:00:00 2001 From: abh1sar Date: Mon, 25 Aug 2025 18:33:16 +0530 Subject: [PATCH 3/7] Cleanup MultiNetworkSelection.vue --- ui/src/views/compute/wizard/MultiNetworkSelection.vue | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ui/src/views/compute/wizard/MultiNetworkSelection.vue b/ui/src/views/compute/wizard/MultiNetworkSelection.vue index 4d11aba118aa..ecfbf643385d 100644 --- a/ui/src/views/compute/wizard/MultiNetworkSelection.vue +++ b/ui/src/views/compute/wizard/MultiNetworkSelection.vue @@ -281,10 +281,8 @@ export default { this.sendValuesTimed() }, getDefaultNetwork (record) { - console.log('getDefaultNetwork', record, this.values, this.validNetworks) - if (record.vlanid) { + if (record.vlanid && record.vlanid !== -1) { const matched = this.validNetworks[record.id].filter(x => Number(x.vlan) === record.vlanid) - console.log('matched', matched) if (matched.length > 0) { this.handleNetworkChange(record, matched[0].id) return matched[0].id From 9f78d8fd61876a0202ca26f254eecc51fed4c0e1 Mon Sep 17 00:00:00 2001 From: abh1sar Date: Mon, 25 Aug 2025 18:33:16 +0530 Subject: [PATCH 4/7] getting the vlanid from the /proc/net/vlan/ file instead of the bridge name --- .../resource/LibvirtComputingResource.java | 14 +++++++++++ .../kvm/resource/LibvirtDomainXMLParser.java | 24 ------------------- ...rtGetUnmanagedInstancesCommandWrapper.java | 7 ++++-- .../LibvirtReplugNicCommandWrapperTest.java | 3 --- 4 files changed, 19 insertions(+), 29 deletions(-) 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 19c6e7145a6d..2d63a6696612 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 @@ -1797,6 +1797,20 @@ private String matchPifFileInDirectory(final String bridgeName) { return ""; } + public Integer getVlanIdForBridge(final String bridge) { + String pif = matchPifFileInDirectory(bridge); + final File vlanfile = new File("/proc/net/vlan/" + pif); + if (vlanfile.isFile()) { + String vlan = Script.runSimpleBashScript("awk '/VID:/ {print $3}' /proc/net/vlan/" + pif); + try { + return Integer.parseInt(vlan); + } catch (final NumberFormatException e) { + return null; + } + } + return null; + } + static String [] ifNamePatterns = { "^eth", "^bond", diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java index 6ad7a7ccbb09..c4d5ac48f6f8 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java @@ -241,12 +241,6 @@ public boolean parseDomainXML(String domXML) { } else if (type.equalsIgnoreCase("bridge")) { String bridge = getAttrValue("source", "bridge", nic); def.defBridgeNet(bridge, dev, mac, NicModel.valueOf(model.toUpperCase()), networkRateKBps); - if (StringUtils.isNotBlank(bridge)) { - Integer vlanId = extractVlanFromBridgeName(bridge); - if (vlanId != null) { - def.setVlanTag(vlanId); - } - } } else if (type.equalsIgnoreCase("ethernet")) { String scriptPath = getAttrValue("script", "path", nic); def.defEthernet(dev, mac, NicModel.valueOf(model.toUpperCase()), scriptPath, networkRateKBps); @@ -575,22 +569,4 @@ private void extractCpuModeDef(final Element rootElement){ } } } - - private Integer extractVlanFromBridgeName(String bridge) { - if (!bridge.startsWith("br")) { - return null; - } - String[] splitByDash = bridge.split("-"); - if (splitByDash.length < 2) { - return null; - } - try { - Integer vlanId = Integer.parseInt(splitByDash[splitByDash.length - 1]); - if (vlanId >=1 && vlanId <= 4094) { - return vlanId; - } - } catch (NumberFormatException e) { - } - return null; - } } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java index 70b1715cc20a..07a455fb662a 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java @@ -132,7 +132,7 @@ private UnmanagedInstanceTO getUnmanagedInstance(LibvirtComputingResource libvir } instance.setPowerState(getPowerState(libvirtComputingResource.getVmState(conn,domain.getName()))); instance.setMemory((int) LibvirtComputingResource.getDomainMemory(domain) / 1024); - instance.setNics(getUnmanagedInstanceNics(parser.getInterfaces())); + instance.setNics(getUnmanagedInstanceNics(libvirtComputingResource, parser.getInterfaces())); instance.setDisks(getUnmanagedInstanceDisks(parser.getDisks(),libvirtComputingResource, conn, domain.getName())); instance.setVncPassword(getFormattedVncPassword(parser.getVncPasswd())); @@ -163,7 +163,7 @@ private UnmanagedInstanceTO.PowerState getPowerState(VirtualMachine.PowerState v } } - private List getUnmanagedInstanceNics(List interfaces) { + private List getUnmanagedInstanceNics(LibvirtComputingResource libvirtComputingResource, List interfaces) { final ArrayList nics = new ArrayList<>(interfaces.size()); int counter = 0; for (LibvirtVMDef.InterfaceDef interfaceDef : interfaces) { @@ -174,6 +174,9 @@ private List getUnmanagedInstanceNics(List\n" + "\n" + "\n" - + "\n" - + "\n" - + "" + "\n" + "\n"; final String expectedAttachXml = From 6943136569dd8b673f32654af24bef6eb8c8df21 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 9 Sep 2025 12:39:12 +0200 Subject: [PATCH 5/7] Update plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java Co-authored-by: dahn --- .../wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java index 07a455fb662a..b2a098563f6e 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java @@ -174,7 +174,8 @@ private List getUnmanagedInstanceNics(LibvirtComputingR nic.setNetwork(interfaceDef.getDevName()); nic.setPciSlot(interfaceDef.getSlot().toString()); nic.setVlan(interfaceDef.getVlanTag()); - if (nic.getVlan() == -1 && interfaceDef.getNetType() == LibvirtVMDef.InterfaceDef.GuestNetType.BRIDGE) { + if (nic.getVlan() == -1 + && LibvirtVMDef.InterfaceDef.GuestNetType.BRIDGE.equals(interfaceDef.getNetType())) { nic.setVlan(libvirtComputingResource.getVlanIdForBridge(interfaceDef.getBrName())); } nics.add(nic); From 896b43b30573287f5bf780684234e841a11a4627 Mon Sep 17 00:00:00 2001 From: Abhisar Sinha <63767682+abh1sar@users.noreply.github.com> Date: Wed, 10 Sep 2025 15:02:41 +0530 Subject: [PATCH 6/7] Don't call sendValuesTimed from getDefaultNetwork as it's causing an infinte loop --- ui/src/views/compute/wizard/MultiNetworkSelection.vue | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ui/src/views/compute/wizard/MultiNetworkSelection.vue b/ui/src/views/compute/wizard/MultiNetworkSelection.vue index ecfbf643385d..111a99ccf7eb 100644 --- a/ui/src/views/compute/wizard/MultiNetworkSelection.vue +++ b/ui/src/views/compute/wizard/MultiNetworkSelection.vue @@ -272,19 +272,22 @@ export default { } this.sendValuesTimed() }, - handleNetworkChange (nic, networkId) { + setNetworkState (nic, networkId) { if (this.hypervisor === 'KVM') { this.setIpAddressEnabled(nic, _.find(this.networks, (option) => option.id === networkId)) } else { this.setIpAddressEnabled(nic, _.find(this.validNetworks[nic.id], (option) => option.id === networkId)) } + }, + handleNetworkChange (nic, networkId) { + this.setNetworkState(nic, networkId) this.sendValuesTimed() }, getDefaultNetwork (record) { if (record.vlanid && record.vlanid !== -1) { const matched = this.validNetworks[record.id].filter(x => Number(x.vlan) === record.vlanid) if (matched.length > 0) { - this.handleNetworkChange(record, matched[0].id) + this.setNetworkState(record, matched[0].id) return matched[0].id } } From ea5e1c0ba578ab6f80ddf684215813cb6903bc54 Mon Sep 17 00:00:00 2001 From: Abhisar Sinha <63767682+abh1sar@users.noreply.github.com> Date: Wed, 10 Sep 2025 20:54:10 +0530 Subject: [PATCH 7/7] set default network values in setDefaultValues instead of getDefaultNetwork --- .../compute/wizard/MultiNetworkSelection.vue | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/ui/src/views/compute/wizard/MultiNetworkSelection.vue b/ui/src/views/compute/wizard/MultiNetworkSelection.vue index 111a99ccf7eb..0e9983bc3564 100644 --- a/ui/src/views/compute/wizard/MultiNetworkSelection.vue +++ b/ui/src/views/compute/wizard/MultiNetworkSelection.vue @@ -265,33 +265,32 @@ export default { this.values = {} this.ipAddresses = {} for (const item of this.items) { - var network = this.validNetworks[item.id]?.[0] || null + let network = null + if (item.vlanid && item.vlanid !== -1) { + const matched = this.validNetworks[item.id].filter(x => Number(x.vlan) === item.vlanid) + if (matched.length > 0) { + network = matched[0] + } + } + if (!network) { + network = this.validNetworks[item.id]?.[0] || null + } this.values[item.id] = network ? network.id : '' this.ipAddresses[item.id] = (!network || network.type === 'L2') ? null : 'auto' this.setIpAddressEnabled(item, network) } this.sendValuesTimed() }, - setNetworkState (nic, networkId) { + handleNetworkChange (nic, networkId) { if (this.hypervisor === 'KVM') { this.setIpAddressEnabled(nic, _.find(this.networks, (option) => option.id === networkId)) } else { this.setIpAddressEnabled(nic, _.find(this.validNetworks[nic.id], (option) => option.id === networkId)) } - }, - handleNetworkChange (nic, networkId) { - this.setNetworkState(nic, networkId) this.sendValuesTimed() }, getDefaultNetwork (record) { - if (record.vlanid && record.vlanid !== -1) { - const matched = this.validNetworks[record.id].filter(x => Number(x.vlan) === record.vlanid) - if (matched.length > 0) { - this.setNetworkState(record, matched[0].id) - return matched[0].id - } - } - return this.validNetworks[record.id][0].id + return this.values[record.id] || this.validNetworks[record.id]?.[0]?.id }, sendValuesTimed () { clearTimeout(this.sendValuesTimer)