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.InetAddress;
14 import java.net.Inet6Address;
15 import java.net.UnknownHostException;
16 import java.util.ArrayList;
17 import java.util.Iterator;
18 import java.util.List;
20 import javax.xml.bind.annotation.XmlAccessType;
21 import javax.xml.bind.annotation.XmlAccessorType;
22 import javax.xml.bind.annotation.XmlElement;
23 import javax.xml.bind.annotation.XmlRootElement;
25 import org.apache.commons.net.util.SubnetUtils;
26 import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
32 @XmlAccessorType(XmlAccessType.NONE)
34 public class NeutronSubnet extends NeutronObject implements Serializable, INeutronObject {
35 private static final Logger LOGGER = LoggerFactory
36 .getLogger(NeutronCRUDInterfaces.class);
38 private static final long serialVersionUID = 1L;
39 private static final int IPV4_VERSION = 4;
40 private static final int IPV6_VERSION = 6;
41 private static final int IPV6_LENGTH = 128;
42 private static final int IPV6_LENGTH_BYTES = 8;
43 private static final long IPV6_LSB_MASK = 0x000000FF;
44 private static final int IPV6_BYTE_OFFSET = 7;
46 // See OpenStack Network API v2.0 Reference for description of
47 // annotated attributes
49 @XmlElement (name = "network_id")
52 @XmlElement (name = "name")
55 @XmlElement (defaultValue = "4", name = "ip_version")
58 @XmlElement (name = "cidr")
61 @XmlElement (name = "gateway_ip")
64 @XmlElement (name = "dns_nameservers")
65 List<String> dnsNameservers;
67 @XmlElement (name = "allocation_pools")
68 List<NeutronSubnetIPAllocationPool> allocationPools;
70 @XmlElement (name = "host_routes")
71 List<NeutronRoute> hostRoutes;
73 @XmlElement (defaultValue = "true", name = "enable_dhcp")
76 @XmlElement (name = "ipv6_address_mode", nillable = true)
77 String ipV6AddressMode;
79 @XmlElement (name = "ipv6_ra_mode", nillable = true)
82 public String getNetworkUUID() {
86 public void setNetworkUUID(String networkUUID) {
87 this.networkUUID = networkUUID;
90 public String getName() {
94 public void setName(String name) {
98 public Integer getIpVersion() {
102 public void setIpVersion(Integer ipVersion) {
103 this.ipVersion = ipVersion;
106 public String getCidr() {
110 public void setCidr(String cidr) {
114 public String getGatewayIP() {
118 public void setGatewayIP(String gatewayIP) {
119 this.gatewayIP = gatewayIP;
122 public List<String> getDnsNameservers() {
123 return dnsNameservers;
126 public void setDnsNameservers(List<String> dnsNameservers) {
127 this.dnsNameservers = dnsNameservers;
130 public List<NeutronSubnetIPAllocationPool> getAllocationPools() {
131 return allocationPools;
134 public void setAllocationPools(List<NeutronSubnetIPAllocationPool> allocationPools) {
135 this.allocationPools = allocationPools;
138 public List<NeutronRoute> getHostRoutes() {
142 public void setHostRoutes(List<NeutronRoute> hostRoutes) {
143 this.hostRoutes = hostRoutes;
146 public boolean isEnableDHCP() {
147 if (enableDHCP == null) {
153 public Boolean getEnableDHCP() { return enableDHCP; }
155 public void setEnableDHCP(Boolean newValue) {
156 enableDHCP = newValue;
159 public String getIpV6AddressMode() { return ipV6AddressMode; }
161 public void setIpV6AddressMode(String ipV6AddressMode) { this.ipV6AddressMode = ipV6AddressMode; }
163 public String getIpV6RaMode() { return ipV6RaMode; }
165 public void setIpV6RaMode(String ipV6RaMode) { this.ipV6RaMode = ipV6RaMode; }
168 * This method copies selected fields from the object and returns them
169 * as a new object, suitable for marshaling.
172 * List of attributes to be extracted
173 * @return an OpenStackSubnets object with only the selected fields
177 public NeutronSubnet extractFields(List<String> fields) {
178 NeutronSubnet ans = new NeutronSubnet();
179 Iterator<String> i = fields.iterator();
180 while (i.hasNext()) {
182 if (s.equals("id")) {
183 ans.setID(this.getID());
185 if (s.equals("network_id")) {
186 ans.setNetworkUUID(this.getNetworkUUID());
188 if (s.equals("name")) {
189 ans.setName(this.getName());
191 if (s.equals("ip_version")) {
192 ans.setIpVersion(this.getIpVersion());
194 if (s.equals("cidr")) {
195 ans.setCidr(this.getCidr());
197 if (s.equals("gateway_ip")) {
198 ans.setGatewayIP(this.getGatewayIP());
200 if (s.equals("dns_nameservers")) {
201 List<String> nsList = new ArrayList<String>();
202 nsList.addAll(this.getDnsNameservers());
203 ans.setDnsNameservers(nsList);
205 if (s.equals("allocation_pools")) {
206 List<NeutronSubnetIPAllocationPool> aPools = new ArrayList<NeutronSubnetIPAllocationPool>();
207 aPools.addAll(this.getAllocationPools());
208 ans.setAllocationPools(aPools);
210 if (s.equals("host_routes")) {
211 List<NeutronRoute> hRoutes = new ArrayList<NeutronRoute>();
212 hRoutes.addAll(this.getHostRoutes());
213 ans.setHostRoutes(hRoutes);
215 if (s.equals("enable_dhcp")) {
216 ans.setEnableDHCP(this.getEnableDHCP());
218 if (s.equals("tenant_id")) {
219 ans.setTenantID(this.getTenantID());
221 if (s.equals("ipv6_address_mode")) {
222 ans.setIpV6AddressMode(this.getIpV6AddressMode());
224 if (s.equals("ipv6_ra_mode")) {
225 ans.setIpV6RaMode(this.getIpV6RaMode());
231 /* test to see if the cidr address used to define this subnet
232 * is a valid network address (an necessary condition when creating
235 public boolean isValidCIDR() {
236 // fix for Bug 2290 - need to wrap the existing test as
237 // IPv4 because SubnetUtils doesn't support IPv6
238 if (ipVersion == IPV4_VERSION) {
240 SubnetUtils util = new SubnetUtils(cidr);
241 SubnetInfo info = util.getInfo();
242 if (!info.getNetworkAddress().equals(info.getAddress())) {
245 } catch (IllegalArgumentException e) {
246 LOGGER.warn("Failure in isValidCIDR()", e);
251 if (ipVersion == IPV6_VERSION) {
252 // fix for Bug2290 - this is custom code because no classes
253 // with ODL-friendly licenses have been found
254 // extract address (in front of /) and length (after /)
255 String[] parts = cidr.split("/");
256 if (parts.length != 2) {
260 int length = Integer.parseInt(parts[1]);
261 //TODO?: limit check on length
262 // convert to byte array
263 byte[] addrBytes = ((Inet6Address) InetAddress.getByName(parts[0])).getAddress();
265 for (i = length; i < IPV6_LENGTH; i++) {
266 if (((((int) addrBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES)))) != 0) {
271 } catch (UnknownHostException e) {
272 LOGGER.warn("Failure in isValidCIDR()", e);
279 /* test to see if the gateway IP specified overlaps with specified
280 * allocation pools (an error condition when creating a new subnet
281 * or assigning a gateway IP)
283 public boolean gatewayIP_Pool_overlap() {
284 Iterator<NeutronSubnetIPAllocationPool> i = allocationPools.iterator();
285 while (i.hasNext()) {
286 NeutronSubnetIPAllocationPool pool = i.next();
287 if (ipVersion == IPV4_VERSION && pool.contains(gatewayIP)) {
290 if (ipVersion == IPV6_VERSION && pool.containsV6(gatewayIP)) {
298 public void initDefaults() {
299 if (enableDHCP == null) {
302 if (ipVersion == null) {
303 ipVersion = IPV4_VERSION;
305 if (dnsNameservers == null) {
306 dnsNameservers = new ArrayList<String>();
308 if (hostRoutes == null) {
309 hostRoutes = new ArrayList<NeutronRoute>();
311 if (allocationPools == null) {
312 allocationPools = new ArrayList<NeutronSubnetIPAllocationPool>();
313 if (ipVersion == IPV4_VERSION) {
315 SubnetUtils util = new SubnetUtils(cidr);
316 SubnetInfo info = util.getInfo();
317 if (gatewayIP == null || ("").equals(gatewayIP)) {
318 gatewayIP = info.getLowAddress();
320 if (allocationPools.size() < 1) {
321 NeutronSubnetIPAllocationPool source =
322 new NeutronSubnetIPAllocationPool(info.getLowAddress(),
323 info.getHighAddress());
324 allocationPools = source.splitPool(gatewayIP);
326 } catch (IllegalArgumentException e) {
327 LOGGER.warn("Failure in initDefault()", e);
331 if (ipVersion == IPV6_VERSION) {
332 String[] parts = cidr.split("/");
333 if (parts.length != 2) {
337 int length = Integer.parseInt(parts[1]);
338 BigInteger lowAddress_bi = NeutronSubnetIPAllocationPool.convertV6(parts[0]);
339 String lowAddress = NeutronSubnetIPAllocationPool.bigIntegerToIP(lowAddress_bi.add(BigInteger.ONE));
340 BigInteger mask = BigInteger.ONE.shiftLeft(length).subtract(BigInteger.ONE);
341 String highAddress = NeutronSubnetIPAllocationPool.bigIntegerToIP(lowAddress_bi.add(mask).subtract(BigInteger.ONE));
342 if (gatewayIP == null || ("").equals(gatewayIP)) {
343 gatewayIP = lowAddress;
345 if (allocationPools.size() < 1) {
346 NeutronSubnetIPAllocationPool source =
347 new NeutronSubnetIPAllocationPool(lowAddress,
349 allocationPools = source.splitPoolV6(gatewayIP);
351 } catch (Exception e) {
352 LOGGER.warn("Failure in initDefault()", e);
359 /* this method tests to see if the supplied IPv4 address
360 * is valid for this subnet or not
362 public boolean isValidIP(String ipAddress) {
363 if (ipVersion == IPV4_VERSION) {
365 SubnetUtils util = new SubnetUtils(cidr);
366 SubnetInfo info = util.getInfo();
367 return info.isInRange(ipAddress);
368 } catch (IllegalArgumentException e) {
369 LOGGER.warn("Failure in isValidIP()", e);
374 if (ipVersion == IPV6_VERSION) {
375 String[] parts = cidr.split("/");
377 int length = Integer.parseInt(parts[1]);
378 byte[] cidrBytes = ((Inet6Address) InetAddress.getByName(parts[0])).getAddress();
379 byte[] ipBytes = ((Inet6Address) InetAddress.getByName(ipAddress)).getAddress();
381 for (i = 0; i < length; i++) {
382 if (((((int) cidrBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES)))) !=
383 ((((int) ipBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES))))) {
388 } catch (UnknownHostException e) {
389 LOGGER.warn("Failure in isValidIP()", e);
396 /* method to get the lowest available address of the subnet.
397 * go through all the allocation pools and keep the lowest of their
400 public String getLowAddr() {
402 Iterator<NeutronSubnetIPAllocationPool> i = allocationPools.iterator();
403 while (i.hasNext()) {
404 NeutronSubnetIPAllocationPool pool = i.next();
406 ans = pool.getPoolStart();
409 if (ipVersion == IPV4_VERSION &&
410 NeutronSubnetIPAllocationPool.convert(pool.getPoolStart()) <
411 NeutronSubnetIPAllocationPool.convert(ans)) {
412 ans = pool.getPoolStart();
414 if (ipVersion == IPV6_VERSION &&
415 NeutronSubnetIPAllocationPool.convertV6(pool.getPoolStart()).compareTo(NeutronSubnetIPAllocationPool.convertV6(ans)) < 0) {
416 ans = pool.getPoolStart();
424 public String toString() {
425 return "NeutronSubnet [subnetUUID=" + uuid + ", networkUUID=" + networkUUID + ", name=" + name
426 + ", ipVersion=" + ipVersion + ", cidr=" + cidr + ", gatewayIP=" + gatewayIP + ", dnsNameservers="
427 + dnsNameservers + ", allocationPools=" + allocationPools + ", hostRoutes=" + hostRoutes
428 + ", enableDHCP=" + enableDHCP + ", tenantID=" + tenantID
429 + ", ipv6AddressMode=" + ipV6AddressMode
430 + ", ipv6RaMode=" + ipV6RaMode + "]";