2 * Copyright (c) 2013, 2015 IBM Corporation and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.neutron.spi;
11 import com.google.common.net.InetAddresses;
12 import java.io.Serializable;
13 import java.math.BigInteger;
14 import java.net.Inet6Address;
15 import java.util.ArrayList;
16 import java.util.List;
17 import javax.xml.bind.annotation.XmlAccessType;
18 import javax.xml.bind.annotation.XmlAccessorType;
19 import javax.xml.bind.annotation.XmlElement;
20 import javax.xml.bind.annotation.XmlRootElement;
21 import org.apache.commons.net.util.SubnetUtils;
22 import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
27 @XmlAccessorType(XmlAccessType.NONE)
28 public final class NeutronSubnet extends NeutronBaseAttributes<NeutronSubnet> implements Serializable {
29 private static final Logger LOGGER = LoggerFactory.getLogger(NeutronCRUDInterfaces.class);
31 private static final long serialVersionUID = 1L;
32 private static final int IPV4_VERSION = 4;
33 private static final int IPV6_VERSION = 6;
34 private static final int IPV6_LENGTH = 128;
35 private static final int IPV6_LENGTH_BYTES = 8;
36 private static final long IPV6_LSB_MASK = 0x000000FF;
37 private static final int IPV6_BYTE_OFFSET = 7;
39 // See OpenStack Network API v2.0 Reference for description of
40 // annotated attributes
42 @XmlElement(name = "network_id")
45 @XmlElement(defaultValue = "4", name = "ip_version")
48 @XmlElement(name = "cidr")
51 @XmlElement(name = "gateway_ip")
54 @XmlElement(name = "dns_nameservers")
55 List<String> dnsNameservers;
57 @XmlElement(name = "allocation_pools")
58 List<NeutronSubnetIpAllocationPool> allocationPools;
60 @XmlElement(name = "host_routes")
61 List<NeutronRoute> hostRoutes;
63 @XmlElement(defaultValue = "true", name = "enable_dhcp")
66 @XmlElement(name = "ipv6_address_mode", nillable = true)
67 String ipV6AddressMode;
69 @XmlElement(name = "ipv6_ra_mode", nillable = true)
72 public String getNetworkUUID() {
76 public void setNetworkUUID(String networkUUID) {
77 this.networkUUID = networkUUID;
80 public Integer getIpVersion() {
84 public void setIpVersion(Integer ipVersion) {
85 this.ipVersion = ipVersion;
88 public String getCidr() {
92 public void setCidr(String cidr) {
96 public String getGatewayIp() {
100 public void setGatewayIp(String gatewayIp) {
101 this.gatewayIp = gatewayIp;
104 public List<String> getDnsNameservers() {
105 return dnsNameservers;
108 public void setDnsNameservers(List<String> dnsNameservers) {
109 this.dnsNameservers = dnsNameservers;
112 public List<NeutronSubnetIpAllocationPool> getAllocationPools() {
113 return allocationPools;
116 public void setAllocationPools(List<NeutronSubnetIpAllocationPool> allocationPools) {
117 this.allocationPools = allocationPools;
120 public List<NeutronRoute> getHostRoutes() {
124 public void setHostRoutes(List<NeutronRoute> hostRoutes) {
125 this.hostRoutes = hostRoutes;
128 public boolean isEnableDHCP() {
129 if (enableDHCP == null) {
135 public Boolean getEnableDHCP() {
139 public void setEnableDHCP(Boolean newValue) {
140 enableDHCP = newValue;
143 public String getIpV6AddressMode() {
144 return ipV6AddressMode;
147 public void setIpV6AddressMode(String ipV6AddressMode) {
148 this.ipV6AddressMode = ipV6AddressMode;
151 public String getIpV6RaMode() {
155 public void setIpV6RaMode(String ipV6RaMode) {
156 this.ipV6RaMode = ipV6RaMode;
160 * This method copies selected fields from the object and returns them
161 * as a new object, suitable for marshaling.
164 * List of attributes to be extracted
165 * @return an OpenStackSubnets object with only the selected fields
169 public NeutronSubnet extractFields(List<String> fields) {
170 NeutronSubnet ans = new NeutronSubnet();
171 for (String s : fields) {
172 if (extractField(s, ans)) {
177 ans.setNetworkUUID(this.getNetworkUUID());
180 ans.setIpVersion(this.getIpVersion());
183 ans.setCidr(this.getCidr());
186 ans.setGatewayIp(this.getGatewayIp());
188 case "dns_nameservers":
189 List<String> nsList = new ArrayList<String>();
190 nsList.addAll(this.getDnsNameservers());
191 ans.setDnsNameservers(nsList);
193 case "allocation_pools":
194 List<NeutronSubnetIpAllocationPool> pools = new ArrayList<NeutronSubnetIpAllocationPool>();
195 pools.addAll(this.getAllocationPools());
196 ans.setAllocationPools(pools);
199 List<NeutronRoute> hostRoutes = new ArrayList<NeutronRoute>();
200 hostRoutes.addAll(this.getHostRoutes());
201 ans.setHostRoutes(hostRoutes);
204 ans.setEnableDHCP(this.getEnableDHCP());
206 case "ipv6_address_mode":
207 ans.setIpV6AddressMode(this.getIpV6AddressMode());
210 ans.setIpV6RaMode(this.getIpV6RaMode());
213 LOGGER.warn("{} is not an OpenStackSubnet suitable field.", s);
220 /* test to see if the cidr address used to define this subnet
221 * is a valid network address (an necessary condition when creating
224 public boolean isValidCIDR() {
225 // fix for Bug 2290 - need to wrap the existing test as
226 // IPv4 because SubnetUtils doesn't support IPv6
227 if (ipVersion == IPV4_VERSION) {
229 SubnetUtils util = new SubnetUtils(cidr);
230 SubnetInfo info = util.getInfo();
231 if (!info.getNetworkAddress().equals(info.getAddress())) {
234 } catch (IllegalArgumentException e) {
235 LOGGER.warn("Failure in isValidCIDR()", e);
240 if (ipVersion == IPV6_VERSION) {
241 // fix for Bug2290 - this is custom code because no classes
242 // with ODL-friendly licenses have been found
243 // extract address (in front of /) and length (after /)
244 String[] parts = cidr.split("/");
245 if (parts.length != 2) {
248 int length = Integer.parseInt(parts[1]);
249 //TODO?: limit check on length
250 // convert to byte array
251 byte[] addrBytes = ((Inet6Address) InetAddresses.forString(parts[0])).getAddress();
252 for (int index = length; index < IPV6_LENGTH; index++) {
253 if (((((int) addrBytes[index / IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK)
254 & (1 << (IPV6_BYTE_OFFSET - (index % IPV6_LENGTH_BYTES)))) != 0) {
263 /* test to see if the gateway IP specified overlaps with specified
264 * allocation pools (an error condition when creating a new subnet
265 * or assigning a gateway IP)
267 public boolean gatewayIp_Pool_overlap() {
268 for (NeutronSubnetIpAllocationPool pool : allocationPools) {
269 if (ipVersion == IPV4_VERSION && pool.contains(gatewayIp)) {
272 if (ipVersion == IPV6_VERSION && pool.containsV6(gatewayIp)) {
280 public void initDefaults() {
281 if (enableDHCP == null) {
284 if (ipVersion == null) {
285 ipVersion = IPV4_VERSION;
287 if (dnsNameservers == null) {
288 dnsNameservers = new ArrayList<String>();
290 if (hostRoutes == null) {
291 hostRoutes = new ArrayList<NeutronRoute>();
293 if (allocationPools == null) {
294 allocationPools = new ArrayList<NeutronSubnetIpAllocationPool>();
295 if (ipVersion == IPV4_VERSION) {
297 SubnetUtils util = new SubnetUtils(cidr);
298 SubnetInfo info = util.getInfo();
299 if (gatewayIp == null || ("").equals(gatewayIp)) {
300 gatewayIp = info.getLowAddress();
302 if (allocationPools.size() < 1) {
303 NeutronSubnetIpAllocationPool source = new NeutronSubnetIpAllocationPool(info.getLowAddress(),
304 info.getHighAddress());
305 allocationPools = source.splitPool(gatewayIp);
307 } catch (IllegalArgumentException e) {
308 LOGGER.warn("Failure in initDefault()", e);
312 if (ipVersion == IPV6_VERSION) {
313 String[] parts = cidr.split("/");
314 if (parts.length != 2) {
318 int length = Integer.parseInt(parts[1]);
319 BigInteger lowAddressBi = NeutronSubnetIpAllocationPool.convertV6(parts[0]);
320 String lowAddress = NeutronSubnetIpAllocationPool.bigIntegerToIp(lowAddressBi.add(BigInteger.ONE));
321 BigInteger mask = BigInteger.ONE.shiftLeft(length).subtract(BigInteger.ONE);
322 String highAddress = NeutronSubnetIpAllocationPool
323 .bigIntegerToIp(lowAddressBi.add(mask).subtract(BigInteger.ONE));
324 if (gatewayIp == null || ("").equals(gatewayIp)) {
325 gatewayIp = lowAddress;
327 if (allocationPools.size() < 1) {
328 NeutronSubnetIpAllocationPool source = new NeutronSubnetIpAllocationPool(lowAddress,
330 allocationPools = source.splitPoolV6(gatewayIp);
336 /* this method tests to see if the supplied IPv4 address
337 * is valid for this subnet or not
339 public boolean isValidIp(String ipAddress) {
340 if (ipVersion == IPV4_VERSION) {
342 SubnetUtils util = new SubnetUtils(cidr);
343 SubnetInfo info = util.getInfo();
344 return info.isInRange(ipAddress);
345 } catch (IllegalArgumentException e) {
346 LOGGER.warn("Failure in isValidIp()", e);
351 if (ipVersion == IPV6_VERSION) {
352 String[] parts = cidr.split("/");
353 int length = Integer.parseInt(parts[1]);
354 byte[] cidrBytes = ((Inet6Address) InetAddresses.forString(parts[0])).getAddress();
355 byte[] ipBytes = ((Inet6Address) InetAddresses.forString(ipAddress)).getAddress();
356 for (int index = 0; index < length; index++) {
357 if (((((int) cidrBytes[index / IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET
358 - (index % IPV6_LENGTH_BYTES)))) != (
359 (((int) ipBytes[index / IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK)
360 & (1 << (IPV6_BYTE_OFFSET - (index % IPV6_LENGTH_BYTES))))) {
369 /* method to get the lowest available address of the subnet.
370 * go through all the allocation pools and keep the lowest of their
373 public String getLowAddr() {
375 for (NeutronSubnetIpAllocationPool pool : allocationPools) {
377 ans = pool.getPoolStart();
379 if (ipVersion == IPV4_VERSION && NeutronSubnetIpAllocationPool
380 .convert(pool.getPoolStart()) < NeutronSubnetIpAllocationPool.convert(ans)) {
381 ans = pool.getPoolStart();
383 if (ipVersion == IPV6_VERSION && NeutronSubnetIpAllocationPool.convertV6(pool.getPoolStart())
384 .compareTo(NeutronSubnetIpAllocationPool.convertV6(ans)) < 0) {
385 ans = pool.getPoolStart();
393 public String toString() {
394 return "NeutronSubnet [subnetUUID=" + uuid + ", networkUUID=" + networkUUID + ", name=" + name + ", ipVersion="
395 + ipVersion + ", cidr=" + cidr + ", gatewayIp=" + gatewayIp + ", dnsNameservers=" + dnsNameservers
396 + ", allocationPools=" + allocationPools + ", hostRoutes=" + hostRoutes + ", enableDHCP=" + enableDHCP
397 + ", tenantID=" + tenantID + ", ipv6AddressMode=" + ipV6AddressMode + ", ipv6RaMode=" + ipV6RaMode