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 LOG = 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 protected boolean extractField(String field, NeutronSubnet ans) {
163 ans.setNetworkUUID(this.getNetworkUUID());
166 ans.setIpVersion(this.getIpVersion());
169 ans.setCidr(this.getCidr());
172 ans.setGatewayIp(this.getGatewayIp());
174 case "dns_nameservers":
175 List<String> nsList = new ArrayList<>();
176 nsList.addAll(this.getDnsNameservers());
177 ans.setDnsNameservers(nsList);
179 case "allocation_pools":
180 List<NeutronSubnetIpAllocationPool> pools = new ArrayList<>();
181 pools.addAll(this.getAllocationPools());
182 ans.setAllocationPools(pools);
185 List<NeutronRoute> routes = new ArrayList<>();
186 routes.addAll(this.getHostRoutes());
187 ans.setHostRoutes(routes);
190 ans.setEnableDHCP(this.getEnableDHCP());
192 case "ipv6_address_mode":
193 ans.setIpV6AddressMode(this.getIpV6AddressMode());
196 ans.setIpV6RaMode(this.getIpV6RaMode());
199 return super.extractField(field, ans);
204 /* test to see if the cidr address used to define this subnet
205 * is a valid network address (an necessary condition when creating
208 public boolean isValidCIDR() {
209 // fix for Bug 2290 - need to wrap the existing test as
210 // IPv4 because SubnetUtils doesn't support IPv6
211 if (ipVersion == IPV4_VERSION) {
213 SubnetUtils util = new SubnetUtils(cidr);
214 SubnetInfo info = util.getInfo();
215 if (!info.getNetworkAddress().equals(info.getAddress())) {
218 } catch (IllegalArgumentException e) {
219 LOG.warn("Failure in isValidCIDR()", e);
224 if (ipVersion == IPV6_VERSION) {
225 // fix for Bug2290 - this is custom code because no classes
226 // with ODL-friendly licenses have been found
227 // extract address (in front of /) and length (after /)
228 String[] parts = cidr.split("/");
229 if (parts.length != 2) {
232 int length = Integer.parseInt(parts[1]);
233 //TODO?: limit check on length
234 // convert to byte array
235 byte[] addrBytes = ((Inet6Address) InetAddresses.forString(parts[0])).getAddress();
236 for (int index = length; index < IPV6_LENGTH; index++) {
237 if (((((int) addrBytes[index / IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK)
238 & (1 << (IPV6_BYTE_OFFSET - (index % IPV6_LENGTH_BYTES)))) != 0) {
247 /* test to see if the gateway IP specified overlaps with specified
248 * allocation pools (an error condition when creating a new subnet
249 * or assigning a gateway IP)
251 public boolean gatewayIp_Pool_overlap() {
252 for (NeutronSubnetIpAllocationPool pool : allocationPools) {
253 if (ipVersion == IPV4_VERSION && pool.contains(gatewayIp)) {
256 if (ipVersion == IPV6_VERSION && pool.containsV6(gatewayIp)) {
264 public void initDefaults() {
265 if (enableDHCP == null) {
268 if (ipVersion == null) {
269 ipVersion = IPV4_VERSION;
271 if (dnsNameservers == null) {
272 dnsNameservers = new ArrayList<>();
274 if (hostRoutes == null) {
275 hostRoutes = new ArrayList<>();
277 if (allocationPools == null) {
278 allocationPools = new ArrayList<>();
279 if (ipVersion == IPV4_VERSION) {
281 SubnetUtils util = new SubnetUtils(cidr);
282 SubnetInfo info = util.getInfo();
283 if (gatewayIp == null || ("").equals(gatewayIp)) {
284 gatewayIp = info.getLowAddress();
286 if (allocationPools.size() < 1) {
287 NeutronSubnetIpAllocationPool source = new NeutronSubnetIpAllocationPool(info.getLowAddress(),
288 info.getHighAddress());
289 allocationPools = source.splitPool(gatewayIp);
291 } catch (IllegalArgumentException e) {
292 LOG.warn("Failure in initDefault()", e);
296 if (ipVersion == IPV6_VERSION) {
297 String[] parts = cidr.split("/");
298 if (parts.length != 2) {
302 int length = Integer.parseInt(parts[1]);
303 BigInteger lowAddressBi = NeutronSubnetIpAllocationPool.convertV6(parts[0]);
304 String lowAddress = NeutronSubnetIpAllocationPool.bigIntegerToIp(lowAddressBi.add(BigInteger.ONE));
305 BigInteger mask = BigInteger.ONE.shiftLeft(length).subtract(BigInteger.ONE);
306 String highAddress = NeutronSubnetIpAllocationPool
307 .bigIntegerToIp(lowAddressBi.add(mask).subtract(BigInteger.ONE));
308 if (gatewayIp == null || ("").equals(gatewayIp)) {
309 gatewayIp = lowAddress;
311 if (allocationPools.size() < 1) {
312 NeutronSubnetIpAllocationPool source = new NeutronSubnetIpAllocationPool(lowAddress,
314 allocationPools = source.splitPoolV6(gatewayIp);
320 /* this method tests to see if the supplied IPv4 address
321 * is valid for this subnet or not
323 public boolean isValidIp(String ipAddress) {
324 if (ipVersion == IPV4_VERSION) {
326 SubnetUtils util = new SubnetUtils(cidr);
327 SubnetInfo info = util.getInfo();
328 return info.isInRange(ipAddress);
329 } catch (IllegalArgumentException e) {
330 LOG.warn("Failure in isValidIp()", e);
335 if (ipVersion == IPV6_VERSION) {
336 String[] parts = cidr.split("/");
337 int length = Integer.parseInt(parts[1]);
338 byte[] cidrBytes = ((Inet6Address) InetAddresses.forString(parts[0])).getAddress();
339 byte[] ipBytes = ((Inet6Address) InetAddresses.forString(ipAddress)).getAddress();
340 for (int index = 0; index < length; index++) {
341 if (((((int) cidrBytes[index / IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET
342 - (index % IPV6_LENGTH_BYTES)))) != (
343 (((int) ipBytes[index / IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK)
344 & (1 << (IPV6_BYTE_OFFSET - (index % IPV6_LENGTH_BYTES))))) {
353 /* method to get the lowest available address of the subnet.
354 * go through all the allocation pools and keep the lowest of their
357 public String getLowAddr() {
359 for (NeutronSubnetIpAllocationPool pool : allocationPools) {
361 ans = pool.getPoolStart();
363 if (ipVersion == IPV4_VERSION && NeutronSubnetIpAllocationPool
364 .convert(pool.getPoolStart()) < NeutronSubnetIpAllocationPool.convert(ans)) {
365 ans = pool.getPoolStart();
367 if (ipVersion == IPV6_VERSION && NeutronSubnetIpAllocationPool.convertV6(pool.getPoolStart())
368 .compareTo(NeutronSubnetIpAllocationPool.convertV6(ans)) < 0) {
369 ans = pool.getPoolStart();
377 public String toString() {
378 return "NeutronSubnet [subnetUUID=" + uuid + ", networkUUID=" + networkUUID + ", name=" + name + ", ipVersion="
379 + ipVersion + ", cidr=" + cidr + ", gatewayIp=" + gatewayIp + ", dnsNameservers=" + dnsNameservers
380 + ", allocationPools=" + allocationPools + ", hostRoutes=" + hostRoutes + ", enableDHCP=" + enableDHCP
381 + ", tenantID=" + tenantID + ", ipv6AddressMode=" + ipV6AddressMode + ", ipv6RaMode=" + ipV6RaMode