Merge pull request #1883 from Accelerite/uniqueMac

CLOUDSTACK-9723: Enable unique mac address across the zones
This commit is contained in:
Rajani Karuturi 2017-05-17 10:36:19 +05:30 committed by GitHub
commit 339fe4c7bd
16 changed files with 85 additions and 19 deletions

View File

@ -38,6 +38,7 @@ import com.cloud.user.Account;
import com.cloud.vm.Nic;
import com.cloud.vm.NicProfile;
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.framework.config.ConfigKey;
/**
* The NetworkModel presents a read-only view into the Network data such as L2 networks,
@ -47,6 +48,9 @@ import com.cloud.vm.VirtualMachine;
*/
public interface NetworkModel {
static final ConfigKey<Integer> MACIdentifier = new ConfigKey<Integer>("Advanced",Integer.class, "mac.identifier", "0",
"This value will be used while generating the mac addresses for isolated and shared networks. The hexadecimal equivalent value will be present at the 2nd octet of the mac address. Default value is null which means this feature is disabled.Its scope is global.", true, ConfigKey.Scope.Global);
/**
* Lists IP addresses that belong to VirtualNetwork VLANs
*

View File

@ -20,7 +20,6 @@ import com.cloud.agent.api.Answer;
import com.cloud.agent.manager.Commands;
import com.cloud.deploy.DeployDestination;
import com.cloud.exception.ResourceUnavailableException;
/**
* A VirtualMachineGuru knows how to process a certain type of virtual machine.
*

View File

@ -20,6 +20,7 @@ import java.util.Date;
import com.cloud.dc.VlanVO;
import com.cloud.network.IpAddress;
import com.cloud.network.NetworkModel;
import com.cloud.network.PublicIpAddress;
import com.cloud.network.dao.IPAddressVO;
import com.cloud.utils.net.Ip;
@ -39,7 +40,7 @@ public class PublicIp implements PublicIpAddress {
}
public static PublicIp createFromAddrAndVlan(IPAddressVO addr, VlanVO vlan) {
return new PublicIp(addr, vlan, NetUtils.createSequenceBasedMacAddress(addr.getMacAddress()));
return new PublicIp(addr, vlan, NetUtils.createSequenceBasedMacAddress(addr.getMacAddress(), NetworkModel.MACIdentifier.value()));
}
@Override
@ -249,7 +250,9 @@ public class PublicIp implements PublicIpAddress {
}
@Override
public Class<?> getEntityType() {
public Class<?> getEntityType()
{
return IpAddress.class;
}
}

View File

@ -54,9 +54,10 @@ public interface NetworkDao extends GenericDao<NetworkVO, Long>, StateDao<State,
*
* @param networkConfigId
* id
* @param zoneMacIdentifier
* @return mac address if there is one. null if not.
*/
String getNextAvailableMacAddress(long networkConfigId);
String getNextAvailableMacAddress(long networkConfigId, Integer zoneMacIdentifier);
List<NetworkVO> listBy(long accountId, long networkId);

View File

@ -377,11 +377,15 @@ public class NetworkDaoImpl extends GenericDaoBase<NetworkVO, Long> implements N
}
@Override
public String getNextAvailableMacAddress(final long networkConfigId) {
public String getNextAvailableMacAddress(final long networkConfigId, Integer zoneMacIdentifier) {
final SequenceFetcher fetch = SequenceFetcher.getInstance();
long seq = fetch.getNextSequence(Long.class, _tgMacAddress, networkConfigId);
seq = seq | _prefix << 40 | _rand.nextInt(Short.MAX_VALUE) << 16 & 0x00000000ffff0000l;
if(zoneMacIdentifier != null && zoneMacIdentifier.intValue() != 0 ){
seq = seq | _prefix << 40 | (long)zoneMacIdentifier << 32 | networkConfigId << 16 & 0x00000000ffff0000l;
}
else {
seq = seq | _prefix << 40 | _rand.nextInt(Short.MAX_VALUE) << 16 & 0x00000000ffff0000l;
}
return NetUtils.long2Mac(seq);
}

View File

@ -742,7 +742,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
} else {
type = c.getType();
}
//no need to validate further if a
//config can have null value.
String errMsg = null;
try {
if (type.equals(Integer.class)) {
@ -791,6 +792,20 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
return null;
}
if (type.equals(Integer.class) && NetworkModel.MACIdentifier.key().equalsIgnoreCase(name)) {
try {
final int val = Integer.parseInt(value);
//The value need to be between 0 to 255 because the mac generation needs a value of 8 bit
//0 value is considered as disable.
if(val < 0 || val > 255){
throw new InvalidParameterValueException(name+" value should be between 0 and 255. 0 value will disable this feature");
}
} catch (final NumberFormatException e) {
s_logger.error("There was an error trying to parse the integer value for:" + name);
throw new InvalidParameterValueException("There was an error trying to parse the integer value for:" + name);
}
}
if (type.equals(Integer.class) && configValuesForValidation.contains(name)) {
try {
final int val = Integer.parseInt(value);

View File

@ -22,6 +22,7 @@ import com.cloud.user.Account;
import com.cloud.utils.component.Manager;
public interface Ipv6AddressManager extends Manager {
public UserIpv6Address assignDirectIp6Address(long dcId, Account owner, Long networkId, String requestedIp6) throws InsufficientAddressCapacityException;
public void revokeDirectIpv6Address(long networkId, String ip6Address);

View File

@ -132,7 +132,7 @@ public class Ipv6AddressManagerImpl extends ManagerBase implements Ipv6AddressMa
dc.setMacAddress(nextMac);
_dcDao.update(dc.getId(), dc);
String macAddress = NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(mac));
String macAddress = NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(mac,NetworkModel.MACIdentifier.value()));
UserIpv6AddressVO ipVO = new UserIpv6AddressVO(ip, dcId, macAddress, ipVlan.getId());
ipVO.setPhysicalNetworkId(network.getPhysicalNetworkId());
ipVO.setSourceNetworkId(networkId);

View File

@ -34,6 +34,8 @@ import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao;
import org.apache.commons.codec.binary.Base64;
@ -124,7 +126,7 @@ import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.NicSecondaryIpDao;
import com.cloud.vm.dao.VMInstanceDao;
public class NetworkModelImpl extends ManagerBase implements NetworkModel {
public class NetworkModelImpl extends ManagerBase implements NetworkModel, Configurable {
static final Logger s_logger = Logger.getLogger(NetworkModelImpl.class);
@Inject
EntityManager _entityMgr;
@ -561,7 +563,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel {
@Override
public String getNextAvailableMacAddressInNetwork(long networkId) throws InsufficientAddressCapacityException {
String mac = _networksDao.getNextAvailableMacAddress(networkId);
NetworkVO network = _networksDao.findById(networkId);
String mac = _networksDao.getNextAvailableMacAddress(networkId, MACIdentifier.value());
if (mac == null) {
throw new InsufficientAddressCapacityException("Unable to create another mac address", Network.class, networkId);
}
@ -2364,4 +2367,14 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel {
return vmData;
}
@Override
public String getConfigComponentName() {
return NetworkModel.class.getSimpleName();
}
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {MACIdentifier};
}
}

View File

@ -20,6 +20,7 @@ import java.util.Random;
import javax.inject.Inject;
import com.cloud.network.NetworkModel;
import org.apache.log4j.Logger;
import com.cloud.dc.Pod;
@ -53,6 +54,7 @@ public class PodBasedNetworkGuru extends AdapterBase implements NetworkGuru {
DataCenterDao _dcDao;
@Inject
StorageNetworkManager _sNwMgr;
Random _rand = new Random(System.currentTimeMillis());
private static final TrafficType[] TrafficTypes = {TrafficType.Management};
@ -123,7 +125,7 @@ public class PodBasedNetworkGuru extends AdapterBase implements NetworkGuru {
}
nic.setIPv4Address(ip.first());
nic.setMacAddress(NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(ip.second())));
nic.setMacAddress(NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(ip.second(), NetworkModel.MACIdentifier.value())));
nic.setIPv4Gateway(pod.getGateway());
nic.setFormat(AddressFormat.Ip4);
String netmask = NetUtils.getCidrNetmask(pod.getCidrSize());

View File

@ -186,7 +186,7 @@ public class PrivateNetworkGuru extends AdapterBase implements NetworkGuru {
String vlanTag = BroadcastDomainType.getValue(network.getBroadcastUri());
String netmask = NetUtils.getCidrNetmask(network.getCidr());
PrivateIpAddress ip =
new PrivateIpAddress(ipVO, vlanTag, network.getGateway(), netmask, NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(ipVO.getMacAddress())));
new PrivateIpAddress(ipVO, vlanTag, network.getGateway(), netmask, NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(ipVO.getMacAddress(), NetworkModel.MACIdentifier.value())));
nic.setIPv4Address(ip.getIpAddress());
nic.setIPv4Gateway(ip.getGateway());

View File

@ -18,6 +18,7 @@ package com.cloud.network.guru;
import javax.inject.Inject;
import com.cloud.network.NetworkModel;
import org.apache.log4j.Logger;
import com.cloud.dc.Pod;
@ -131,7 +132,7 @@ public class StorageNetworkGuru extends PodBasedNetworkGuru implements NetworkGu
vlan = ip.getVlan();
nic.setIPv4Address(ip.getIpAddress());
nic.setMacAddress(NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(ip.getMac())));
nic.setMacAddress(NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(ip.getMac(), NetworkModel.MACIdentifier.value())));
nic.setFormat(AddressFormat.Ip4);
nic.setIPv4Netmask(ip.getNetmask());
nic.setBroadcastType(BroadcastDomainType.Storage);

View File

@ -87,14 +87,14 @@ public class NicProfileHelperImpl implements NicProfileHelper {
router.getHypervisorType(), privateNetwork));
if (router.getIsRedundantRouter()) {
String newMacAddress = NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(ipVO.getMacAddress()));
String newMacAddress = NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(ipVO.getMacAddress(), NetworkModel.MACIdentifier.value()));
privateNicProfile.setMacAddress(newMacAddress);
}
} else {
final String netmask = NetUtils.getCidrNetmask(privateNetwork.getCidr());
final PrivateIpAddress ip =
new PrivateIpAddress(ipVO, privateNetwork.getBroadcastUri().toString(), privateNetwork.getGateway(), netmask,
NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(ipVO.getMacAddress())));
NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(ipVO.getMacAddress(), NetworkModel.MACIdentifier.value())));
final URI netUri = BroadcastDomainType.fromString(ip.getBroadcastUri());
privateNicProfile.setIPv4Address(ip.getIpAddress());

View File

@ -106,7 +106,7 @@ public class MockNetworkDaoImpl extends GenericDaoBase<NetworkVO, Long> implemen
* @see com.cloud.network.dao.NetworkDao#getNextAvailableMacAddress(long)
*/
@Override
public String getNextAvailableMacAddress(final long networkConfigId) {
public String getNextAvailableMacAddress(final long networkConfigId, Integer zoneMacIdentifier) {
// TODO Auto-generated method stub
return null;
}

View File

@ -83,9 +83,19 @@ public class NetUtils {
public final static int DEFAULT_AUTOSCALE_POLICY_INTERVAL_TIME = 30;
public final static int DEFAULT_AUTOSCALE_POLICY_QUIET_TIME = 5 * 60;
private final static Random s_rand = new Random(System.currentTimeMillis());
private final static long prefix = 0x1e;
public static long createSequenceBasedMacAddress(final long macAddress) {
return macAddress | 0x060000000000l | (long)s_rand.nextInt(32768) << 25 & 0x00fffe000000l;
public static long createSequenceBasedMacAddress(final long macAddress, long globalConfig) {
/*
Logic for generating MAC address:
Mac = B1:B2:B3:B4:B5:B6 (Bx is a byte).
B1 -> Presently controlled by prefix variable. The value should be such that the MAC is local and unicast.
B2 -> This will be configurable for each deployment/installation. Controlled by the global config MACIdentifier
B3 -> A randomly generated number between 0 - 255
B4,5,6 -> These bytes are based on the unique DB identifier associated with the IP address for which MAC is generated (refer to mac_address field in user_ip_address table).
*/
return macAddress | prefix<<40 | globalConfig << 32 & 0x00ff00000000l | (long)s_rand.nextInt(255) << 24;
}
public static String getHostName() {

View File

@ -560,6 +560,19 @@ public class NetUtilsTest {
NetUtils.EUI64Address("2001:980:7936::/64", "c0:3f:d5:68:28:08"));
}
@Test
public void testcreateSequenceBasedMacAddress(){
long mac1 = NetUtils.createSequenceBasedMacAddress(10l,10l);
assertEquals(10l,(mac1 & (0x0al<<32)) >> 32);
assertEquals(10l,mac1 & 0x0al);
assertEquals(30l, mac1>>40);
long mac2 = NetUtils.createSequenceBasedMacAddress(20l,15l);
assertEquals(15l, (mac2 & (0x0fl << 32)) >> 32);
assertEquals(20l, mac2 & 0x14l);
assertEquals(30l, mac1>>40);
}
@Test
public void testIPv6LinkLocal() {
assertEquals(IPv6Address.fromString("fe80::fc54:ff:fe00:3e05"), NetUtils.ipv6LinkLocal("fe:54:00:00:3e:05"));