From 0c6cf69eeec940345a6ee01b7d03a184e3c31398 Mon Sep 17 00:00:00 2001 From: sureshanaparti Date: Mon, 21 Aug 2017 14:34:20 +0530 Subject: [PATCH] CLOUDSTACK-9717: [VMware] RVRs have mismatching MAC addresses for extra public NICs. (#1878) Fix: When RVR is enabled and Peer Router is available, get the MAC addresses of the extra public NICs from the Peer Router and set them to the router. --- .../schema/src/com/cloud/vm/dao/NicDao.java | 2 + .../src/com/cloud/vm/dao/NicDaoImpl.java | 20 ++++++ .../com/cloud/hypervisor/guru/VMwareGuru.java | 17 +++++ .../vmware/resource/VmwareResource.java | 65 +++++++++++++++++++ .../vmware/resource/VmwareResourceTest.java | 34 ++++++++++ 5 files changed, 138 insertions(+) diff --git a/engine/schema/src/com/cloud/vm/dao/NicDao.java b/engine/schema/src/com/cloud/vm/dao/NicDao.java index d31a165955f..797f002381b 100644 --- a/engine/schema/src/com/cloud/vm/dao/NicDao.java +++ b/engine/schema/src/com/cloud/vm/dao/NicDao.java @@ -77,5 +77,7 @@ public interface NicDao extends GenericDao { NicVO getControlNicForVM(long vmId); + Long getPeerRouterId(String publicMacAddress, long routerId); + List listByVmIdAndKeyword(long instanceId, String keyword); } diff --git a/engine/schema/src/com/cloud/vm/dao/NicDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/NicDaoImpl.java index a5edf581f2b..daf773afbf7 100644 --- a/engine/schema/src/com/cloud/vm/dao/NicDaoImpl.java +++ b/engine/schema/src/com/cloud/vm/dao/NicDaoImpl.java @@ -45,6 +45,7 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { private SearchBuilder NonReleasedSearch; private GenericSearchBuilder deviceIdSearch; private GenericSearchBuilder CountByForStartingVms; + private SearchBuilder PeerRouterSearch; @Inject VMInstanceDao _vmDao; @@ -94,6 +95,12 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { join1.and("state", join1.entity().getState(), Op.EQ); CountByForStartingVms.join("vm", join1, CountByForStartingVms.entity().getInstanceId(), join1.entity().getId(), JoinBuilder.JoinType.INNER); CountByForStartingVms.done(); + + PeerRouterSearch = createSearchBuilder(); + PeerRouterSearch.and("instanceId", PeerRouterSearch.entity().getInstanceId(), Op.NEQ); + PeerRouterSearch.and("macAddress", PeerRouterSearch.entity().getMacAddress(), Op.EQ); + PeerRouterSearch.and("vmType", PeerRouterSearch.entity().getVmType(), Op.EQ); + PeerRouterSearch.done(); } @Override @@ -312,6 +319,19 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { return results.get(0); } + @Override + public Long getPeerRouterId(String publicMacAddress, final long routerId) { + final SearchCriteria sc = PeerRouterSearch.create(); + sc.setParameters("instanceId", routerId); + sc.setParameters("macAddress", publicMacAddress); + sc.setParameters("vmType", VirtualMachine.Type.DomainRouter); + NicVO nicVo = findOneBy(sc); + if (nicVo != null) { + return nicVo.getInstanceId(); + } + return null; + } + @Override public List listByVmIdAndKeyword(long instanceId, String keyword) { SearchCriteria sc = AllFieldsSearch.create(); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java index 668f4acc454..7b6accf5357 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java @@ -94,6 +94,7 @@ import com.cloud.utils.Pair; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; +import com.cloud.vm.DomainRouterVO; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; import com.cloud.vm.SecondaryStorageVmVO; @@ -101,6 +102,7 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VmDetailConstants; +import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.VMInstanceDao; @@ -128,6 +130,8 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co @Inject private NicDao _nicDao; @Inject + private DomainRouterDao _domainRouterDao; + @Inject private PhysicalNetworkTrafficTypeDao _physicalNetworkTrafficTypeDao; @Inject private VMInstanceDao _vmDao; @@ -296,6 +300,19 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co } to.setNics(expandedNics); + + VirtualMachine router = vm.getVirtualMachine(); + DomainRouterVO routerVO = _domainRouterDao.findById(router.getId()); + if (routerVO != null && routerVO.getIsRedundantRouter()) { + Long peerRouterId = _nicDao.getPeerRouterId(publicNicProfile.getMacAddress(), router.getId()); + DomainRouterVO peerRouterVO = null; + if (peerRouterId != null) { + peerRouterVO = _domainRouterDao.findById(peerRouterId); + if (peerRouterVO != null) { + details.put("PeerRouterInstanceName", peerRouterVO.getInstanceName()); + } + } + } } StringBuffer sbMacSequence = new StringBuffer(); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index bddd61ace01..142d341e19e 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -46,6 +46,7 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import org.apache.log4j.NDC; +import org.apache.commons.lang.StringUtils; import com.google.gson.Gson; import com.vmware.vim25.AboutInfo; @@ -1959,6 +1960,40 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa VirtualDevice nic; int nicMask = 0; int nicCount = 0; + + if (vmSpec.getType() == VirtualMachine.Type.DomainRouter) { + int extraPublicNics = mgr.getRouterExtraPublicNics(); + if (extraPublicNics > 0 && vmSpec.getDetails().containsKey("PeerRouterInstanceName")) { + //Set identical MAC address for RvR on extra public interfaces + String peerRouterInstanceName = vmSpec.getDetails().get("PeerRouterInstanceName"); + + VirtualMachineMO peerVmMo = hyperHost.findVmOnHyperHost(peerRouterInstanceName); + if (peerVmMo == null) { + peerVmMo = hyperHost.findVmOnPeerHyperHost(peerRouterInstanceName); + } + + if (peerVmMo != null) { + String oldMacSequence = generateMacSequence(nics); + + for (int nicIndex = nics.length - extraPublicNics; nicIndex < nics.length; nicIndex++) { + VirtualDevice nicDevice = peerVmMo.getNicDeviceByIndex(nics[nicIndex].getDeviceId()); + if (nicDevice != null) { + String mac = ((VirtualEthernetCard)nicDevice).getMacAddress(); + if (mac != null) { + s_logger.info("Use same MAC as previous RvR, the MAC is " + mac + " for extra NIC with device id: " + nics[nicIndex].getDeviceId()); + nics[nicIndex].setMac(mac); + } + } + } + + if (!StringUtils.isBlank(vmSpec.getBootArgs())) { + String newMacSequence = generateMacSequence(nics); + vmSpec.setBootArgs(replaceNicsMacSequenceInBootArgs(oldMacSequence, newMacSequence, vmSpec)); + } + } + } + } + VirtualEthernetCardType nicDeviceType = VirtualEthernetCardType.valueOf(vmSpec.getDetails().get(VmDetailConstants.NIC_ADAPTER)); if (s_logger.isDebugEnabled()) s_logger.debug("VM " + vmInternalCSName + " will be started with NIC device type: " + nicDeviceType); @@ -2166,6 +2201,36 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } + /** + * Generate the mac sequence from the nics. + */ + protected String generateMacSequence(NicTO[] nics) { + if (nics.length == 0) { + return ""; + } + + StringBuffer sbMacSequence = new StringBuffer(); + for (NicTO nicTo : sortNicsByDeviceId(nics)) { + sbMacSequence.append(nicTo.getMac()).append("|"); + } + if (!sbMacSequence.toString().isEmpty()) { + sbMacSequence.deleteCharAt(sbMacSequence.length() - 1); //Remove extra '|' char appended at the end + } + + return sbMacSequence.toString(); + } + + /** + * Update boot args with the new nic mac addresses. + */ + protected String replaceNicsMacSequenceInBootArgs(String oldMacSequence, String newMacSequence, VirtualMachineTO vmSpec) { + String bootArgs = vmSpec.getBootArgs(); + if (!StringUtils.isBlank(bootArgs) && !StringUtils.isBlank(oldMacSequence) && !StringUtils.isBlank(newMacSequence)) { + return bootArgs.replace(oldMacSequence, newMacSequence); + } + return ""; + } + /** * Sets video card memory to the one provided in detail svga.vramSize (if provided) on {@code vmConfigSpec}. * 64MB was always set before. diff --git a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java index 744c93aa403..c2b3f363883 100644 --- a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java +++ b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java @@ -58,11 +58,13 @@ import com.vmware.vim25.VirtualDevice; import com.vmware.vim25.VirtualDeviceConfigSpec; import com.vmware.vim25.VirtualMachineConfigSpec; import com.vmware.vim25.VirtualMachineVideoCard; + import com.cloud.agent.api.Command; import com.cloud.agent.api.ScaleVmAnswer; import com.cloud.agent.api.ScaleVmCommand; import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.NfsTO; +import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.api.to.VolumeTO; import com.cloud.hypervisor.vmware.mo.DatacenterMO; @@ -215,6 +217,38 @@ public class VmwareResourceTest { verify(_resource).execute(cmd); } + @Test + public void testGenerateMacSequence() { + final NicTO nicTo1 = new NicTO(); + nicTo1.setMac("01:23:45:67:89:AB"); + nicTo1.setDeviceId(1); + + final NicTO nicTo2 = new NicTO(); + nicTo2.setMac("02:00:65:b5:00:03"); + nicTo2.setDeviceId(0); + + //final NicTO [] nicTOs = {nicTO1, nicTO2, nicTO3}; + //final NicTO[] nics = new NicTO[]{nic}; + final NicTO[] nics = new NicTO[] {nicTo1, nicTo2}; + + String macSequence = _resource.generateMacSequence(nics); + assertEquals(macSequence, "02:00:65:b5:00:03|01:23:45:67:89:AB"); + } + + @Test + public void testReplaceNicsMacSequenceInBootArgs() { + String bootArgs = "nic_macs=02:00:65:b5:00:03|7C02:00:4f:1b:00:15|7C1e:00:54:00:00:0f|7C02:00:35:fa:00:11|7C02:00:47:40:00:12"; + doReturn(bootArgs).when(vmSpec).getBootArgs(); + + String oldMacSequence = "7C02:00:35:fa:00:11|7C02:00:47:40:00:12"; + String newMacSequence = "7C02:00:0c:1d:00:1d|7C02:00:68:0f:00:1e"; + + String updatedBootArgs = _resource.replaceNicsMacSequenceInBootArgs(oldMacSequence, newMacSequence, vmSpec); + + String newBootArgs = "nic_macs=02:00:65:b5:00:03|7C02:00:4f:1b:00:15|7C1e:00:54:00:00:0f|7C02:00:0c:1d:00:1d|7C02:00:68:0f:00:1e"; + assertEquals(newBootArgs, updatedBootArgs); + } + @Test public void testConfigureVideoCardSvgaVramProvided() throws Exception { Map specDetails = new HashMap();