From 3c97325d61079985bb242c59828210adde7368d3 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Wed, 7 Oct 2026 07:04:34 -0300 Subject: [PATCH 1/2] Fix External-DHCP IP fetch records Windows APIPA address on L2 networks --- .../LibvirtGetVmIpAddressCommandWrapper.java | 14 +++++- ...bvirtGetVmIpAddressCommandWrapperTest.java | 50 +++++++++++++++++++ .../java/com/cloud/vm/UserVmManagerImpl.java | 12 ++++- .../java/com/cloud/utils/net/NetUtils.java | 27 ++++++++++ .../com/cloud/utils/net/NetUtilsTest.java | 22 ++++++++ 5 files changed, 122 insertions(+), 3 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java index c7fde1414101..6e5e71f56bd8 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java @@ -130,10 +130,20 @@ private Pair getIpAddresses(String output, String macAddress) { found = true; String ipFamily = parts[parts.length - 2]; String ipPart = parts[parts.length - 1].split("/")[0]; + // Skip link-local addresses (e.g. Windows APIPA 169.254.0.0/16 before a DHCP lease is obtained), + // they are not routable and must not be reported as the instance IP if (ipFamily.equals("ipv4")) { - ipv4 = ipPart; + if (NetUtils.isLinkLocalIp4(ipPart)) { + logger.debug(String.format("Ignoring link-local ipv4 %s with mac address %s", ipPart, macAddress)); + } else { + ipv4 = ipPart; + } } else if (ipFamily.equals("ipv6")) { - ipv6 = ipPart; + if (NetUtils.isLinkLocalIp6(ipPart)) { + logger.debug(String.format("Ignoring link-local ipv6 %s with mac address %s", ipPart, macAddress)); + } else { + ipv6 = ipPart; + } } } logger.debug(String.format("Found ipv4: %s and ipv6: %s with mac address %s", ipv4, ipv6, macAddress)); diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapperTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapperTest.java index f104eadd18be..b1d6e8d99643 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapperTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapperTest.java @@ -58,6 +58,24 @@ public class LibvirtGetVmIpAddressCommandWrapperTest { " Loopback Pseudo-Interface 1 ipv6 ::1/128\n" + // " - - ipv4 127.0.0.1/8\n"; + // Windows guest that has not obtained a DHCP lease yet and self-assigned an APIPA address + private static String VIRSH_DOMIF_OUTPUT_WINDOWS_APIPA = " Name MAC address Protocol Address\n" + // + "-------------------------------------------------------------------------------\n" + // + " Ethernet 02:01:00:d0:00:87 ipv6 fe80::df84:2984:e396:8ac3%6/64\n" + // + " - - ipv4 169.254.149.120/16\n" + // + " Loopback Pseudo-Interface 1 ipv6 ::1/128\n" + // + " - - ipv4 127.0.0.1/8\n"; + + // Same Windows guest once the DHCP lease has been obtained + private static String VIRSH_DOMIF_OUTPUT_WINDOWS_DHCP = " Name MAC address Protocol Address\n" + // + "-------------------------------------------------------------------------------\n" + // + " Ethernet 02:01:00:d0:00:87 ipv6 fd00:ac19:0:1910:0:d3fc:4177:2c32/128\n" + // + " - - ipv6 fe80::df84:2984:e396:8ac3%6/64\n" + // + " - - ipv4 172.25.16.236/22\n" + // + " - - ipv4 169.254.149.120/16\n" + // + " Loopback Pseudo-Interface 1 ipv6 ::1/128\n" + // + " - - ipv4 127.0.0.1/8\n"; + @Before public void setUp() { MockitoAnnotations.openMocks(this); @@ -324,6 +342,38 @@ public void testIpFromWindowsRegistryCommandExecutionFailure() { } } + private Answer executeOnL2Network(String domIfOutput, boolean windows) { + LibvirtComputingResource libvirtComputingResource = mock(LibvirtComputingResource.class); + GetVmIpAddressCommand getVmIpAddressCommand = mock(GetVmIpAddressCommand.class); + LibvirtGetVmIpAddressCommandWrapper commandWrapper = new LibvirtGetVmIpAddressCommandWrapper(); + try (MockedStatic