Import KVM VM: Autodetect vlan id from bridge name (#11507)

* Get vlan from bridge name while importing kvm instances

* Fix LibvirtReplugNicCommandWrapperTest

* Cleanup MultiNetworkSelection.vue

* getting the vlanid from the /proc/net/vlan/<pif> file instead of the bridge name

* Update plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetUnmanagedInstancesCommandWrapper.java

Co-authored-by: dahn <daan.hoogland@gmail.com>

* Don't call sendValuesTimed from getDefaultNetwork as it's causing an infinte loop

* set default network values in setDefaultValues instead of getDefaultNetwork

---------

Co-authored-by: Wei Zhou <weizhou@apache.org>
Co-authored-by: dahn <daan.hoogland@gmail.com>
This commit is contained in:
Abhisar Sinha 2025-09-11 14:09:09 +05:30 committed by GitHub
parent 5d32492676
commit e64e94ad3f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 34 additions and 4 deletions

View File

@ -1797,6 +1797,20 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
return ""; 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 = { static String [] ifNamePatterns = {
"^eth", "^eth",
"^bond", "^bond",

View File

@ -132,7 +132,7 @@ public final class LibvirtGetUnmanagedInstancesCommandWrapper extends CommandWra
} }
instance.setPowerState(getPowerState(libvirtComputingResource.getVmState(conn,domain.getName()))); instance.setPowerState(getPowerState(libvirtComputingResource.getVmState(conn,domain.getName())));
instance.setMemory((int) LibvirtComputingResource.getDomainMemory(domain) / 1024); 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.setDisks(getUnmanagedInstanceDisks(parser.getDisks(),libvirtComputingResource, conn, domain.getName()));
instance.setVncPassword(getFormattedVncPassword(parser.getVncPasswd())); instance.setVncPassword(getFormattedVncPassword(parser.getVncPasswd()));
if (parser.getBootType() != null) { if (parser.getBootType() != null) {
@ -169,7 +169,7 @@ public final class LibvirtGetUnmanagedInstancesCommandWrapper extends CommandWra
} }
} }
private List<UnmanagedInstanceTO.Nic> getUnmanagedInstanceNics(List<LibvirtVMDef.InterfaceDef> interfaces) { private List<UnmanagedInstanceTO.Nic> getUnmanagedInstanceNics(LibvirtComputingResource libvirtComputingResource, List<LibvirtVMDef.InterfaceDef> interfaces) {
final ArrayList<UnmanagedInstanceTO.Nic> nics = new ArrayList<>(interfaces.size()); final ArrayList<UnmanagedInstanceTO.Nic> nics = new ArrayList<>(interfaces.size());
int counter = 0; int counter = 0;
for (LibvirtVMDef.InterfaceDef interfaceDef : interfaces) { for (LibvirtVMDef.InterfaceDef interfaceDef : interfaces) {
@ -180,6 +180,10 @@ public final class LibvirtGetUnmanagedInstancesCommandWrapper extends CommandWra
nic.setNetwork(interfaceDef.getDevName()); nic.setNetwork(interfaceDef.getDevName());
nic.setPciSlot(interfaceDef.getSlot().toString()); nic.setPciSlot(interfaceDef.getSlot().toString());
nic.setVlan(interfaceDef.getVlanTag()); nic.setVlan(interfaceDef.getVlanTag());
if (nic.getVlan() == -1
&& LibvirtVMDef.InterfaceDef.GuestNetType.BRIDGE.equals(interfaceDef.getNetType())) {
nic.setVlan(libvirtComputingResource.getVlanIdForBridge(interfaceDef.getBrName()));
}
nics.add(nic); nics.add(nic);
} }
return nics; return nics;

View File

@ -47,7 +47,7 @@
<a-select <a-select
style="width: 100%" style="width: 100%"
v-if="validNetworks[record.id] && validNetworks[record.id].length > 0" v-if="validNetworks[record.id] && validNetworks[record.id].length > 0"
:defaultValue="validNetworks[record.id][0].id" :defaultValue="getDefaultNetwork(record)"
@change="val => handleNetworkChange(record, val)" @change="val => handleNetworkChange(record, val)"
showSearch showSearch
optionFilterProp="label" optionFilterProp="label"
@ -265,7 +265,16 @@ export default {
this.values = {} this.values = {}
this.ipAddresses = {} this.ipAddresses = {}
for (const item of this.items) { 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.values[item.id] = network ? network.id : ''
this.ipAddresses[item.id] = (!network || network.type === 'L2') ? null : 'auto' this.ipAddresses[item.id] = (!network || network.type === 'L2') ? null : 'auto'
this.setIpAddressEnabled(item, network) this.setIpAddressEnabled(item, network)
@ -280,6 +289,9 @@ export default {
} }
this.sendValuesTimed() this.sendValuesTimed()
}, },
getDefaultNetwork (record) {
return this.values[record.id] || this.validNetworks[record.id]?.[0]?.id
},
sendValuesTimed () { sendValuesTimed () {
clearTimeout(this.sendValuesTimer) clearTimeout(this.sendValuesTimer)
this.sendValuesTimer = setTimeout(() => { this.sendValuesTimer = setTimeout(() => {