Skip to content

Commit 2bad9a6

Browse files
nathanejohnsonyadvr
authored andcommitted
CLOUDSTACK-9949: add ability to specify mac address (#2143)
Added ability to specify mac in deployVirtualMachine and addNicToVirtualMachine api endpoints. Validates mac address to be in the form of: aa:bb:cc:dd:ee:ff , aa-bb-cc-dd-ee-ff , or aa.bb.cc.dd.ee.ff. Ensures that mac address is a Unicast mac. Ensures that the mac address is not already allocated for the specified network.
1 parent 2ccea13 commit 2bad9a6

17 files changed

Lines changed: 210 additions & 18 deletions

File tree

api/src/com/cloud/network/Network.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,26 @@ private State(String description) {
277277
public class IpAddresses {
278278
private String ip4Address;
279279
private String ip6Address;
280+
private String macAddress;
281+
282+
public String getMacAddress() {
283+
return macAddress;
284+
}
285+
286+
public void setMacAddress(String macAddress) {
287+
this.macAddress = macAddress;
288+
}
280289

281290
public IpAddresses(String ip4Address, String ip6Address) {
282291
setIp4Address(ip4Address);
283292
setIp6Address(ip6Address);
284293
}
285294

295+
public IpAddresses(String ipAddress, String ip6Address, String macAddress) {
296+
this(ipAddress, ip6Address);
297+
setMacAddress(macAddress);
298+
}
299+
286300
public String getIp4Address() {
287301
return ip4Address;
288302
}

api/src/com/cloud/network/NetworkModel.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.cloud.exception.InvalidParameterValueException;
2828
import com.cloud.hypervisor.Hypervisor.HypervisorType;
2929
import com.cloud.network.Network.Capability;
30+
import com.cloud.network.Network.IpAddresses;
3031
import com.cloud.network.Network.Provider;
3132
import com.cloud.network.Network.Service;
3233
import com.cloud.network.Networks.TrafficType;
@@ -260,7 +261,7 @@ public interface NetworkModel {
260261

261262
void checkIp6Parameters(String startIPv6, String endIPv6, String ip6Gateway, String ip6Cidr) throws InvalidParameterValueException;
262263

263-
void checkRequestedIpAddresses(long networkId, String ip4, String ip6) throws InvalidParameterValueException;
264+
void checkRequestedIpAddresses(long networkId, IpAddresses ips) throws InvalidParameterValueException;
264265

265266
String getStartIpv6Address(long id);
266267

api/src/com/cloud/vm/NicProfile.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ public NicProfile(String requestedIPv4, String requestedIPv6) {
114114
this.requestedIPv6 = requestedIPv6;
115115
}
116116

117+
public NicProfile(String requestedIPv4, String requestedIPv6, String requestedMacAddress) {
118+
this(requestedIPv4, requestedIPv6);
119+
this.macAddress = requestedMacAddress;
120+
}
121+
117122
public NicProfile(ReservationStrategy strategy, String iPv4Address, String macAddress, String iPv4gateway, String iPv4netmask) {
118123
format = AddressFormat.Ip4;
119124
this.iPv4Address = iPv4Address;

api/src/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ public class ApiConstants {
172172
public static final String LUN = "lun";
173173
public static final String LBID = "lbruleid";
174174
public static final String MAX = "max";
175+
public static final String MAC_ADDRESS = "macaddress";
175176
public static final String MAX_SNAPS = "maxsnaps";
176177
public static final String MEMORY = "memory";
177178
public static final String MODE = "mode";

api/src/org/apache/cloudstack/api/command/user/vm/AddNicToVMCmd.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@
3636
import org.apache.cloudstack.context.CallContext;
3737

3838
import com.cloud.event.EventTypes;
39+
import com.cloud.exception.InvalidParameterValueException;
3940
import com.cloud.user.Account;
4041
import com.cloud.uservm.UserVm;
42+
import com.cloud.utils.net.NetUtils;
4143
import com.cloud.vm.VirtualMachine;
4244

4345
@APICommand(name = "addNicToVirtualMachine", description = "Adds VM to specified network by creating a NIC", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class},
@@ -60,6 +62,9 @@ public class AddNicToVMCmd extends BaseAsyncCmd {
6062
@Parameter(name = ApiConstants.IP_ADDRESS, type = CommandType.STRING, description = "IP Address for the new network")
6163
private String ipaddr;
6264

65+
@Parameter(name = ApiConstants.MAC_ADDRESS, type = CommandType.STRING, description = "Mac Address for the new network")
66+
private String macaddr;
67+
6368
/////////////////////////////////////////////////////
6469
/////////////////// Accessors ///////////////////////
6570
/////////////////////////////////////////////////////
@@ -76,6 +81,18 @@ public String getIpAddress() {
7681
return ipaddr;
7782
}
7883

84+
public String getMacAddress() {
85+
if (macaddr == null) {
86+
return null;
87+
}
88+
if(!NetUtils.isValidMac(macaddr)) {
89+
throw new InvalidParameterValueException("Mac address is not valid: " + macaddr);
90+
} else if(!NetUtils.isUnicastMac(macaddr)) {
91+
throw new InvalidParameterValueException("Mac address is not unicast: " + macaddr);
92+
}
93+
return NetUtils.standardizeMacAddress(macaddr);
94+
}
95+
7996
/////////////////////////////////////////////////////
8097
/////////////// API Implementation///////////////////
8198
/////////////////////////////////////////////////////

api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
147147
private List<String> securityGroupNameList;
148148

149149
@Parameter(name = ApiConstants.IP_NETWORK_LIST, type = CommandType.MAP, description = "ip to network mapping. Can't be specified with networkIds parameter."
150-
+ " Example: iptonetworklist[0].ip=10.10.10.11&iptonetworklist[0].ipv6=fc00:1234:5678::abcd&iptonetworklist[0].networkid=uuid - requests to use ip 10.10.10.11 in network id=uuid")
150+
+ " Example: iptonetworklist[0].ip=10.10.10.11&iptonetworklist[0].ipv6=fc00:1234:5678::abcd&iptonetworklist[0].networkid=uuid&iptonetworklist[0].mac=aa:bb:cc:dd:ee::ff - requests to use ip 10.10.10.11 in network id=uuid")
151151
private Map ipToNetworkList;
152152

153153
@Parameter(name = ApiConstants.IP_ADDRESS, type = CommandType.STRING, description = "the ip address for default vm's network")
@@ -156,6 +156,9 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
156156
@Parameter(name = ApiConstants.IP6_ADDRESS, type = CommandType.STRING, description = "the ipv6 address for default vm's network")
157157
private String ip6Address;
158158

159+
@Parameter(name = ApiConstants.MAC_ADDRESS, type = CommandType.STRING, description = "the mac address for default vm's network")
160+
private String macAddress;
161+
159162
@Parameter(name = ApiConstants.KEYBOARD, type = CommandType.STRING, description = "an optional keyboard device type for the virtual machine. valid value can be one of de,de-ch,es,fi,fr,fr-be,fr-ch,is,it,jp,nl-be,no,pt,uk,us")
160163
private String keyboard;
161164

@@ -333,10 +336,19 @@ public Map<Long, IpAddresses> getIpToNetworkMap() {
333336
}
334337
String requestedIp = ips.get("ip");
335338
String requestedIpv6 = ips.get("ipv6");
339+
String requestedMac = ips.get("mac");
336340
if (requestedIpv6 != null) {
337341
requestedIpv6 = NetUtils.standardizeIp6Address(requestedIpv6);
338342
}
339-
IpAddresses addrs = new IpAddresses(requestedIp, requestedIpv6);
343+
if (requestedMac != null) {
344+
if(!NetUtils.isValidMac(requestedMac)) {
345+
throw new InvalidParameterValueException("Mac address is not valid: " + requestedMac);
346+
} else if(!NetUtils.isUnicastMac(requestedMac)) {
347+
throw new InvalidParameterValueException("Mac address is not unicast: " + requestedMac);
348+
}
349+
requestedMac = NetUtils.standardizeMacAddress(requestedMac);
350+
}
351+
IpAddresses addrs = new IpAddresses(requestedIp, requestedIpv6, requestedMac);
340352
ipToNetworkMap.put(networkId, addrs);
341353
}
342354
}
@@ -355,6 +367,19 @@ public String getIp6Address() {
355367
return NetUtils.standardizeIp6Address(ip6Address);
356368
}
357369

370+
371+
public String getMacAddress() {
372+
if (macAddress == null) {
373+
return null;
374+
}
375+
if(!NetUtils.isValidMac(macAddress)) {
376+
throw new InvalidParameterValueException("Mac address is not valid: " + macAddress);
377+
} else if(!NetUtils.isUnicastMac(macAddress)) {
378+
throw new InvalidParameterValueException("Mac address is not unicast: " + macAddress);
379+
}
380+
return NetUtils.standardizeMacAddress(macAddress);
381+
}
382+
358383
public List<Long> getAffinityGroupIdList() {
359384
if (affinityGroupNameList != null && affinityGroupIdList != null) {
360385
throw new InvalidParameterValueException("affinitygroupids parameter is mutually exclusive with affinitygroupnames parameter");

engine/schema/src/com/cloud/vm/dao/NicDao.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ public interface NicDao extends GenericDao<NicVO, Long> {
4444

4545
NicVO findByIp4AddressAndNetworkId(String ip4Address, long networkId);
4646

47+
NicVO findByNetworkIdAndMacAddress(long networkId, String mac);
48+
4749
NicVO findDefaultNicForVM(long instanceId);
4850

4951
/**

engine/schema/src/com/cloud/vm/dao/NicDaoImpl.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ protected void init() {
6868
AllFieldsSearch.and("nicid", AllFieldsSearch.entity().getId(), Op.EQ);
6969
AllFieldsSearch.and("strategy", AllFieldsSearch.entity().getReservationStrategy(), Op.EQ);
7070
AllFieldsSearch.and("reserverName",AllFieldsSearch.entity().getReserver(),Op.EQ);
71+
AllFieldsSearch.and("macAddress", AllFieldsSearch.entity().getMacAddress(), Op.EQ);
7172
AllFieldsSearch.done();
7273

7374
IpSearch = createSearchBuilder(String.class);
@@ -198,6 +199,14 @@ public NicVO findByIp4AddressAndNetworkId(String ip4Address, long networkId) {
198199
return findOneBy(sc);
199200
}
200201

202+
@Override
203+
public NicVO findByNetworkIdAndMacAddress(long networkId, String mac) {
204+
SearchCriteria<NicVO> sc = AllFieldsSearch.create();
205+
sc.setParameters("network", networkId);
206+
sc.setParameters("macAddress", mac);
207+
return findOneBy(sc);
208+
}
209+
201210
@Override
202211
public NicVO findDefaultNicForVM(long instanceId) {
203212
SearchCriteria<NicVO> sc = AllFieldsSearch.create();

server/src/com/cloud/network/IpAddressManagerImpl.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1988,7 +1988,9 @@ public void doInTransactionWithoutResult(TransactionStatus status) throws Insuff
19881988
nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(ip.getVlanTag()));
19891989
nic.setFormat(AddressFormat.Ip4);
19901990
nic.setReservationId(String.valueOf(ip.getVlanTag()));
1991-
nic.setMacAddress(ip.getMacAddress());
1991+
if(nic.getMacAddress() == null) {
1992+
nic.setMacAddress(ip.getMacAddress());
1993+
}
19921994
}
19931995
nic.setIPv4Dns1(dc.getDns1());
19941996
nic.setIPv4Dns2(dc.getDns2());
@@ -2010,7 +2012,9 @@ public void doInTransactionWithoutResult(TransactionStatus status) throws Insuff
20102012
nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(vlan.getVlanTag()));
20112013
nic.setFormat(AddressFormat.Ip6);
20122014
nic.setReservationId(String.valueOf(vlan.getVlanTag()));
2013-
nic.setMacAddress(ip.getMacAddress());
2015+
if(nic.getMacAddress() == null) {
2016+
nic.setMacAddress(ip.getMacAddress());
2017+
}
20142018
}
20152019
}
20162020
nic.setIPv6Dns1(dc.getIp6Dns1());
@@ -2057,8 +2061,9 @@ public void doInTransactionWithoutResult(TransactionStatus status) throws Insuff
20572061

20582062
nic.setBroadcastUri(network.getBroadcastUri());
20592063
nic.setFormat(AddressFormat.Ip4);
2060-
2061-
nic.setMacAddress(_networkModel.getNextAvailableMacAddressInNetwork(network.getId()));
2064+
if(nic.getMacAddress() == null) {
2065+
nic.setMacAddress(_networkModel.getNextAvailableMacAddressInNetwork(network.getId()));
2066+
}
20622067
}
20632068
nic.setIPv4Dns1(dc.getDns1());
20642069
nic.setIPv4Dns2(dc.getDns2());

server/src/com/cloud/network/NetworkModelImpl.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import com.cloud.network.IpAddress.State;
6363
import com.cloud.network.Network.Capability;
6464
import com.cloud.network.Network.GuestType;
65+
import com.cloud.network.Network.IpAddresses;
6566
import com.cloud.network.Network.Provider;
6667
import com.cloud.network.Network.Service;
6768
import com.cloud.network.Networks.TrafficType;
@@ -2169,7 +2170,10 @@ public void checkIp6Parameters(String startIPv6, String endIPv6, String ip6Gatew
21692170
}
21702171

21712172
@Override
2172-
public void checkRequestedIpAddresses(long networkId, String ip4, String ip6) throws InvalidParameterValueException {
2173+
public void checkRequestedIpAddresses(long networkId, IpAddresses ips) throws InvalidParameterValueException {
2174+
String ip4 = ips.getIp4Address();
2175+
String ip6 = ips.getIp6Address();
2176+
String mac = ips.getMacAddress();
21732177
if (ip4 != null) {
21742178
if (!NetUtils.isValidIp(ip4)) {
21752179
throw new InvalidParameterValueException("Invalid specified IPv4 address " + ip4);
@@ -2198,6 +2202,15 @@ public void checkRequestedIpAddresses(long networkId, String ip4, String ip6) th
21982202
throw new InvalidParameterValueException("Requested IPv6 is not in the predefined range!");
21992203
}
22002204
}
2205+
if (mac != null) {
2206+
if(!NetUtils.isValidMac(mac)) {
2207+
throw new InvalidParameterValueException("Invalid specified MAC address " + mac);
2208+
}
2209+
if (_nicDao.findByNetworkIdAndMacAddress(networkId, mac) != null) {
2210+
throw new InvalidParameterValueException("The requested Mac address is already taken! " + mac);
2211+
}
2212+
2213+
}
22012214
}
22022215

22032216
@Override

0 commit comments

Comments
 (0)