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.
This commit is contained in:
sureshanaparti 2017-08-21 14:34:20 +05:30 committed by Rohit Yadav
parent b947eca958
commit 0c6cf69eee
5 changed files with 138 additions and 0 deletions

View File

@ -77,5 +77,7 @@ public interface NicDao extends GenericDao<NicVO, Long> {
NicVO getControlNicForVM(long vmId);
Long getPeerRouterId(String publicMacAddress, long routerId);
List<NicVO> listByVmIdAndKeyword(long instanceId, String keyword);
}

View File

@ -45,6 +45,7 @@ public class NicDaoImpl extends GenericDaoBase<NicVO, Long> implements NicDao {
private SearchBuilder<NicVO> NonReleasedSearch;
private GenericSearchBuilder<NicVO, Integer> deviceIdSearch;
private GenericSearchBuilder<NicVO, Integer> CountByForStartingVms;
private SearchBuilder<NicVO> PeerRouterSearch;
@Inject
VMInstanceDao _vmDao;
@ -94,6 +95,12 @@ public class NicDaoImpl extends GenericDaoBase<NicVO, Long> 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<NicVO, Long> implements NicDao {
return results.get(0);
}
@Override
public Long getPeerRouterId(String publicMacAddress, final long routerId) {
final SearchCriteria<NicVO> 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<NicVO> listByVmIdAndKeyword(long instanceId, String keyword) {
SearchCriteria<NicVO> sc = AllFieldsSearch.create();

View File

@ -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();

View File

@ -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.

View File

@ -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<String, String> specDetails = new HashMap<String, String>();