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 java.io.Serializable;
12 import java.math.BigInteger;
13 import java.net.Inet6Address;
14 import java.net.InetAddress;
15 import java.net.UnknownHostException;
16 import java.util.ArrayList;
17 import java.util.List;
18 import javax.xml.bind.annotation.XmlAccessType;
19 import javax.xml.bind.annotation.XmlAccessorType;
20 import javax.xml.bind.annotation.XmlElement;
21 import javax.xml.bind.annotation.XmlRootElement;
22 import org.apache.commons.net.util.SubnetUtils;
23 import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
28 @XmlAccessorType(XmlAccessType.NONE)
29 public final class NeutronSubnet extends NeutronBaseAttributes<NeutronSubnet> implements Serializable {
30 private static final Logger LOGGER = LoggerFactory.getLogger(NeutronCRUDInterfaces.class);
32 private static final long serialVersionUID = 1L;
33 private static final int IPV4_VERSION = 4;
34 private static final int IPV6_VERSION = 6;
35 private static final int IPV6_LENGTH = 128;
36 private static final int IPV6_LENGTH_BYTES = 8;
37 private static final long IPV6_LSB_MASK = 0x000000FF;
38 private static final int IPV6_BYTE_OFFSET = 7;
40 // See OpenStack Network API v2.0 Reference for description of
41 // annotated attributes
43 @XmlElement(name = "network_id")
46 @XmlElement(defaultValue = "4", name = "ip_version")
49 @XmlElement(name = "cidr")
52 @XmlElement(name = "gateway_ip")
55 @XmlElement(name = "dns_nameservers")
56 List<String> dnsNameservers;
58 @XmlElement(name = "allocation_pools")
59 List<NeutronSubnetIPAllocationPool> allocationPools;
61 @XmlElement(name = "host_routes")
62 List<NeutronRoute> hostRoutes;
64 @XmlElement(defaultValue = "true", name = "enable_dhcp")
67 @XmlElement(name = "ipv6_address_mode", nillable = true)
68 String ipV6AddressMode;
70 @XmlElement(name = "ipv6_ra_mode", nillable = true)
73 public String getNetworkUUID() {
77 public void setNetworkUUID(String networkUUID) {
78 this.networkUUID = networkUUID;
81 public Integer getIpVersion() {
85 public void setIpVersion(Integer ipVersion) {
86 this.ipVersion = ipVersion;
89 public String getCidr() {
93 public void setCidr(String cidr) {
97 public String getGatewayIP() {
101 public void setGatewayIP(String gatewayIP) {
102 this.gatewayIP = gatewayIP;
105 public List<String> getDnsNameservers() {
106 return dnsNameservers;
109 public void setDnsNameservers(List<String> dnsNameservers) {
110 this.dnsNameservers = dnsNameservers;
113 public List<NeutronSubnetIPAllocationPool> getAllocationPools() {
114 return allocationPools;
117 public void setAllocationPools(List<NeutronSubnetIPAllocationPool> allocationPools) {
118 this.allocationPools = allocationPools;
121 public List<NeutronRoute> getHostRoutes() {
125 public void setHostRoutes(List<NeutronRoute> hostRoutes) {
126 this.hostRoutes = hostRoutes;
129 public boolean isEnableDHCP() {
130 if (enableDHCP == null) {
136 public Boolean getEnableDHCP() {
140 public void setEnableDHCP(Boolean newValue) {
141 enableDHCP = newValue;
144 public String getIpV6AddressMode() {
145 return ipV6AddressMode;
148 public void setIpV6AddressMode(String ipV6AddressMode) {
149 this.ipV6AddressMode = ipV6AddressMode;
152 public String getIpV6RaMode() {
156 public void setIpV6RaMode(String ipV6RaMode) {
157 this.ipV6RaMode = ipV6RaMode;
161 * This method copies selected fields from the object and returns them
162 * as a new object, suitable for marshaling.
165 * List of attributes to be extracted
166 * @return an OpenStackSubnets object with only the selected fields
170 public NeutronSubnet extractFields(List<String> fields) {
171 NeutronSubnet ans = new NeutronSubnet();
172 for (String s : fields) {
173 extractField(s, ans);
174 if (s.equals("network_id")) {
175 ans.setNetworkUUID(this.getNetworkUUID());
177 if (s.equals("ip_version")) {
178 ans.setIpVersion(this.getIpVersion());
180 if (s.equals("cidr")) {
181 ans.setCidr(this.getCidr());
183 if (s.equals("gateway_ip")) {
184 ans.setGatewayIP(this.getGatewayIP());
186 if (s.equals("dns_nameservers")) {
187 List<String> nsList = new ArrayList<String>();
188 nsList.addAll(this.getDnsNameservers());
189 ans.setDnsNameservers(nsList);
191 if (s.equals("allocation_pools")) {
192 List<NeutronSubnetIPAllocationPool> pools = new ArrayList<NeutronSubnetIPAllocationPool>();
193 pools.addAll(this.getAllocationPools());
194 ans.setAllocationPools(pools);
196 if (s.equals("host_routes")) {
197 List<NeutronRoute> hostRoutes = new ArrayList<NeutronRoute>();
198 hostRoutes.addAll(this.getHostRoutes());
199 ans.setHostRoutes(hostRoutes);
201 if (s.equals("enable_dhcp")) {
202 ans.setEnableDHCP(this.getEnableDHCP());
204 if (s.equals("ipv6_address_mode")) {
205 ans.setIpV6AddressMode(this.getIpV6AddressMode());
207 if (s.equals("ipv6_ra_mode")) {
208 ans.setIpV6RaMode(this.getIpV6RaMode());
214 /* test to see if the cidr address used to define this subnet
215 * is a valid network address (an necessary condition when creating
218 public boolean isValidCIDR() {
219 // fix for Bug 2290 - need to wrap the existing test as
220 // IPv4 because SubnetUtils doesn't support IPv6
221 if (ipVersion == IPV4_VERSION) {
223 SubnetUtils util = new SubnetUtils(cidr);
224 SubnetInfo info = util.getInfo();
225 if (!info.getNetworkAddress().equals(info.getAddress())) {
228 } catch (IllegalArgumentException e) {
229 LOGGER.warn("Failure in isValidCIDR()", e);
234 if (ipVersion == IPV6_VERSION) {
235 // fix for Bug2290 - this is custom code because no classes
236 // with ODL-friendly licenses have been found
237 // extract address (in front of /) and length (after /)
238 String[] parts = cidr.split("/");
239 if (parts.length != 2) {
243 int length = Integer.parseInt(parts[1]);
244 //TODO?: limit check on length
245 // convert to byte array
246 byte[] addrBytes = ((Inet6Address) InetAddress.getByName(parts[0])).getAddress();
247 for (int index = length; index < IPV6_LENGTH; index++) {
248 if (((((int) addrBytes[index / IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK)
249 & (1 << (IPV6_BYTE_OFFSET - (index % IPV6_LENGTH_BYTES)))) != 0) {
254 } catch (UnknownHostException e) {
255 LOGGER.warn("Failure in isValidCIDR()", e);
262 /* test to see if the gateway IP specified overlaps with specified
263 * allocation pools (an error condition when creating a new subnet
264 * or assigning a gateway IP)
266 public boolean gatewayIP_Pool_overlap() {
267 for (NeutronSubnetIPAllocationPool pool : allocationPools) {
268 if (ipVersion == IPV4_VERSION && pool.contains(gatewayIP)) {
271 if (ipVersion == IPV6_VERSION && pool.containsV6(gatewayIP)) {
279 public void initDefaults() {
280 if (enableDHCP == null) {
283 if (ipVersion == null) {
284 ipVersion = IPV4_VERSION;
286 if (dnsNameservers == null) {
287 dnsNameservers = new ArrayList<String>();
289 if (hostRoutes == null) {
290 hostRoutes = new ArrayList<NeutronRoute>();
292 if (allocationPools == null) {
293 allocationPools = new ArrayList<NeutronSubnetIPAllocationPool>();
294 if (ipVersion == IPV4_VERSION) {
296 SubnetUtils util = new SubnetUtils(cidr);
297 SubnetInfo info = util.getInfo();
298 if (gatewayIP == null || ("").equals(gatewayIP)) {
299 gatewayIP = info.getLowAddress();
301 if (allocationPools.size() < 1) {
302 NeutronSubnetIPAllocationPool source = new NeutronSubnetIPAllocationPool(info.getLowAddress(),
303 info.getHighAddress());
304 allocationPools = source.splitPool(gatewayIP);
306 } catch (IllegalArgumentException e) {
307 LOGGER.warn("Failure in initDefault()", e);
311 if (ipVersion == IPV6_VERSION) {
312 String[] parts = cidr.split("/");
313 if (parts.length != 2) {
317 int length = Integer.parseInt(parts[1]);
318 BigInteger lowAddressBi = NeutronSubnetIPAllocationPool.convertV6(parts[0]);
319 String lowAddress = NeutronSubnetIPAllocationPool.bigIntegerToIP(lowAddressBi.add(BigInteger.ONE));
320 BigInteger mask = BigInteger.ONE.shiftLeft(length).subtract(BigInteger.ONE);
321 String highAddress = NeutronSubnetIPAllocationPool
322 .bigIntegerToIP(lowAddressBi.add(mask).subtract(BigInteger.ONE));
323 if (gatewayIP == null || ("").equals(gatewayIP)) {
324 gatewayIP = lowAddress;
326 if (allocationPools.size() < 1) {
327 NeutronSubnetIPAllocationPool source = new NeutronSubnetIPAllocationPool(lowAddress,
329 allocationPools = source.splitPoolV6(gatewayIP);
335 /* this method tests to see if the supplied IPv4 address
336 * is valid for this subnet or not
338 public boolean isValidIP(String ipAddress) {
339 if (ipVersion == IPV4_VERSION) {
341 SubnetUtils util = new SubnetUtils(cidr);
342 SubnetInfo info = util.getInfo();
343 return info.isInRange(ipAddress);
344 } catch (IllegalArgumentException e) {
345 LOGGER.warn("Failure in isValidIP()", e);
350 if (ipVersion == IPV6_VERSION) {
351 String[] parts = cidr.split("/");
353 int length = Integer.parseInt(parts[1]);
354 byte[] cidrBytes = ((Inet6Address) InetAddress.getByName(parts[0])).getAddress();
355 byte[] ipBytes = ((Inet6Address) InetAddress.getByName(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))))) {
365 } catch (UnknownHostException e) {
366 LOGGER.warn("Failure in isValidIP()", e);
373 /* method to get the lowest available address of the subnet.
374 * go through all the allocation pools and keep the lowest of their
377 public String getLowAddr() {
379 for (NeutronSubnetIPAllocationPool pool : allocationPools) {
381 ans = pool.getPoolStart();
383 if (ipVersion == IPV4_VERSION && NeutronSubnetIPAllocationPool
384 .convert(pool.getPoolStart()) < NeutronSubnetIPAllocationPool.convert(ans)) {
385 ans = pool.getPoolStart();
387 if (ipVersion == IPV6_VERSION && NeutronSubnetIPAllocationPool.convertV6(pool.getPoolStart())
388 .compareTo(NeutronSubnetIPAllocationPool.convertV6(ans)) < 0) {
389 ans = pool.getPoolStart();
397 public String toString() {
398 return "NeutronSubnet [subnetUUID=" + uuid + ", networkUUID=" + networkUUID + ", name=" + name + ", ipVersion="
399 + ipVersion + ", cidr=" + cidr + ", gatewayIP=" + gatewayIP + ", dnsNameservers=" + dnsNameservers
400 + ", allocationPools=" + allocationPools + ", hostRoutes=" + hostRoutes + ", enableDHCP=" + enableDHCP
401 + ", tenantID=" + tenantID + ", ipv6AddressMode=" + ipV6AddressMode + ", ipv6RaMode=" + ipV6RaMode