2 * Copyright IBM Corporation and others, 2013. 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.controller.networkconfig.neutron;
11 import java.io.Serializable;
12 import java.net.InetAddress;
13 import java.net.Inet6Address;
14 import java.util.ArrayList;
15 import java.util.Iterator;
16 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;
23 import org.apache.commons.net.util.SubnetUtils;
24 import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
25 import org.opendaylight.controller.configuration.ConfigurationObject;
28 @XmlAccessorType(XmlAccessType.NONE)
30 public class NeutronSubnet extends ConfigurationObject implements Serializable, INeutronObject {
31 private static final long serialVersionUID = 1L;
33 // See OpenStack Network API v2.0 Reference for description of
34 // annotated attributes
36 @XmlElement (name="id")
39 @XmlElement (name="network_id")
42 @XmlElement (name="name")
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<NeutronSubnet_IPAllocationPool> allocationPools;
60 @XmlElement (name="host_routes")
61 List<NeutronSubnet_HostRoute> hostRoutes;
63 @XmlElement (defaultValue="true", name="enable_dhcp")
66 @XmlElement (name="tenant_id")
69 @XmlElement (name="ipv6_address_mode", nillable=true)
70 String ipV6AddressMode;
72 @XmlElement (name="ipv6_ra_mode", nillable=true)
75 /* stores the OpenStackPorts associated with an instance
76 * used to determine if that instance can be deleted.
78 List<NeutronPort> myPorts;
80 Boolean gatewayIPAssigned;
82 public NeutronSubnet() {
83 myPorts = new ArrayList<NeutronPort>();
86 public String getID() { return subnetUUID; }
88 public void setID(String id) { this.subnetUUID = id; }
90 public String getSubnetUUID() {
94 public void setSubnetUUID(String subnetUUID) {
95 this.subnetUUID = subnetUUID;
98 public String getNetworkUUID() {
102 public void setNetworkUUID(String networkUUID) {
103 this.networkUUID = networkUUID;
106 public String getName() {
110 public void setName(String name) {
114 public Integer getIpVersion() {
118 public void setIpVersion(Integer ipVersion) {
119 this.ipVersion = ipVersion;
122 public String getCidr() {
126 public void setCidr(String cidr) {
130 public String getGatewayIP() {
134 public void setGatewayIP(String gatewayIP) {
135 this.gatewayIP = gatewayIP;
138 public List<String> getDnsNameservers() {
139 return dnsNameservers;
142 public void setDnsNameservers(List<String> dnsNameservers) {
143 this.dnsNameservers = dnsNameservers;
146 public List<NeutronSubnet_IPAllocationPool> getAllocationPools() {
147 return allocationPools;
150 public void setAllocationPools(List<NeutronSubnet_IPAllocationPool> allocationPools) {
151 this.allocationPools = allocationPools;
154 public List<NeutronSubnet_HostRoute> getHostRoutes() {
158 public void setHostRoutes(List<NeutronSubnet_HostRoute> hostRoutes) {
159 this.hostRoutes = hostRoutes;
162 public boolean isEnableDHCP() {
163 if (enableDHCP == null) {
169 public Boolean getEnableDHCP() { return enableDHCP; }
171 public void setEnableDHCP(Boolean newValue) {
172 enableDHCP = newValue;
175 public String getTenantID() {
179 public void setTenantID(String tenantID) {
180 this.tenantID = tenantID;
183 public String getIpV6AddressMode() { return ipV6AddressMode; }
185 public void setIpV6AddressMode(String ipV6AddressMode) { this.ipV6AddressMode = ipV6AddressMode; }
187 public String getIpV6RaMode() { return ipV6RaMode; }
189 public void setIpV6RaMode(String ipV6RaMode) { this.ipV6RaMode = ipV6RaMode; }
192 * This method copies selected fields from the object and returns them
193 * as a new object, suitable for marshaling.
196 * List of attributes to be extracted
197 * @return an OpenStackSubnets object with only the selected fields
201 public NeutronSubnet extractFields(List<String> fields) {
202 NeutronSubnet ans = new NeutronSubnet();
203 Iterator<String> i = fields.iterator();
204 while (i.hasNext()) {
206 if (s.equals("id")) {
207 ans.setSubnetUUID(this.getSubnetUUID());
209 if (s.equals("network_id")) {
210 ans.setNetworkUUID(this.getNetworkUUID());
212 if (s.equals("name")) {
213 ans.setName(this.getName());
215 if (s.equals("ip_version")) {
216 ans.setIpVersion(this.getIpVersion());
218 if (s.equals("cidr")) {
219 ans.setCidr(this.getCidr());
221 if (s.equals("gateway_ip")) {
222 ans.setGatewayIP(this.getGatewayIP());
224 if (s.equals("dns_nameservers")) {
225 List<String> nsList = new ArrayList<String>();
226 nsList.addAll(this.getDnsNameservers());
227 ans.setDnsNameservers(nsList);
229 if (s.equals("allocation_pools")) {
230 List<NeutronSubnet_IPAllocationPool> aPools = new ArrayList<NeutronSubnet_IPAllocationPool>();
231 aPools.addAll(this.getAllocationPools());
232 ans.setAllocationPools(aPools);
234 if (s.equals("host_routes")) {
235 List<NeutronSubnet_HostRoute> hRoutes = new ArrayList<NeutronSubnet_HostRoute>();
236 hRoutes.addAll(this.getHostRoutes());
237 ans.setHostRoutes(hRoutes);
239 if (s.equals("enable_dhcp")) {
240 ans.setEnableDHCP(this.getEnableDHCP());
242 if (s.equals("tenant_id")) {
243 ans.setTenantID(this.getTenantID());
245 if (s.equals("ipv6_address_mode")) {
246 ans.setIpV6AddressMode(this.getIpV6AddressMode());
248 if (s.equals("ipv6_ra_mode")) {
249 ans.setIpV6RaMode(this.getIpV6RaMode());
255 /* test to see if the cidr address used to define this subnet
256 * is a valid network address (an necessary condition when creating
259 public boolean isValidCIDR() {
260 // fix for Bug 2290 - need to wrap the existing test as
261 // IPv4 because SubnetUtils doesn't support IPv6
262 if (ipVersion == 4) {
264 SubnetUtils util = new SubnetUtils(cidr);
265 SubnetInfo info = util.getInfo();
266 if (!info.getNetworkAddress().equals(info.getAddress())) {
269 } catch (Exception e) {
274 if (ipVersion == 6) {
275 // fix for Bug2290 - this is custom code because no classes
276 // with ODL-friendly licenses have been found
277 // extract address (in front of /) and length (after /)
278 String[] parts = cidr.split("/");
279 if (parts.length != 2) {
283 int length = Integer.parseInt(parts[1]);
284 //TODO?: limit check on length
285 // convert to byte array
286 byte[] addrBytes = ((Inet6Address) InetAddress.getByName(parts[0])).getAddress();
288 for (i=length; i<128; i++) { // offset is to ensure proper comparison
289 if (((((int) addrBytes[i/8]) & 0x000000FF) & (1 << (7-(i%8)))) != 0) {
294 } catch (Exception e) {
301 /* test to see if the gateway IP specified overlaps with specified
302 * allocation pools (an error condition when creating a new subnet
303 * or assigning a gateway IP)
305 public boolean gatewayIP_Pool_overlap() {
306 Iterator<NeutronSubnet_IPAllocationPool> i = allocationPools.iterator();
307 while (i.hasNext()) {
308 NeutronSubnet_IPAllocationPool pool = i.next();
309 if (pool.contains(gatewayIP)) {
316 public boolean initDefaults() {
317 if (enableDHCP == null) {
320 if (ipVersion == null) {
323 gatewayIPAssigned = false;
324 dnsNameservers = new ArrayList<String>();
325 if (hostRoutes == null) {
326 hostRoutes = new ArrayList<NeutronSubnet_HostRoute>();
328 if (allocationPools == null) {
329 allocationPools = new ArrayList<NeutronSubnet_IPAllocationPool>();
331 SubnetUtils util = new SubnetUtils(cidr);
332 SubnetInfo info = util.getInfo();
333 if (gatewayIP == null || ("").equals(gatewayIP)) {
334 gatewayIP = info.getLowAddress();
336 if (allocationPools.size() < 1) {
337 NeutronSubnet_IPAllocationPool source =
338 new NeutronSubnet_IPAllocationPool(info.getLowAddress(),
339 info.getHighAddress());
340 allocationPools = source.splitPool(gatewayIP);
342 } catch (Exception e) {
349 public List<NeutronPort> getPortsInSubnet() {
353 public void addPort(NeutronPort port) {
357 public void removePort(NeutronPort port) {
358 myPorts.remove(port);
361 /* this method tests to see if the supplied IPv4 address
362 * is valid for this subnet or not
364 public boolean isValidIP(String ipAddress) {
366 SubnetUtils util = new SubnetUtils(cidr);
367 SubnetInfo info = util.getInfo();
368 return info.isInRange(ipAddress);
369 } catch (Exception e) {
374 /* test to see if the supplied IPv4 address is part of one of the
375 * available allocation pools or not
377 public boolean isIPInUse(String ipAddress) {
378 if (ipAddress.equals(gatewayIP) && !gatewayIPAssigned ) {
381 Iterator<NeutronSubnet_IPAllocationPool> i = allocationPools.iterator();
382 while (i.hasNext()) {
383 NeutronSubnet_IPAllocationPool pool = i.next();
384 if (pool.contains(ipAddress)) {
391 /* method to get the lowest available address of the subnet.
392 * go through all the allocation pools and keep the lowest of their
395 public String getLowAddr() {
397 Iterator<NeutronSubnet_IPAllocationPool> i = allocationPools.iterator();
398 while (i.hasNext()) {
399 NeutronSubnet_IPAllocationPool pool = i.next();
401 ans = pool.getPoolStart();
404 if (NeutronSubnet_IPAllocationPool.convert(pool.getPoolStart()) <
405 NeutronSubnet_IPAllocationPool.convert(ans)) {
406 ans = pool.getPoolStart();
413 * allocate the parameter address. Because this uses an iterator to
414 * check the instance's list of allocation pools and we want to modify
415 * pools while the iterator is being used, it is necessary to
416 * build a new list of allocation pools and replace the list when
417 * finished (otherwise a split will cause undefined iterator behavior.
419 public void allocateIP(String ipAddress) {
420 Iterator<NeutronSubnet_IPAllocationPool> i = allocationPools.iterator();
421 List<NeutronSubnet_IPAllocationPool> newList = new ArrayList<NeutronSubnet_IPAllocationPool>(); // we have to modify a separate list
422 while (i.hasNext()) {
423 NeutronSubnet_IPAllocationPool pool = i.next();
424 /* if the pool contains a single address element and we are allocating it
425 * then we don't need to copy the pool over. Otherwise, we need to possibly
426 * split the pool and add both pieces to the new list
428 if (!(pool.getPoolEnd().equalsIgnoreCase(ipAddress) &&
429 pool.getPoolStart().equalsIgnoreCase(ipAddress))) {
430 if (pool.contains(ipAddress)) {
431 List<NeutronSubnet_IPAllocationPool> pools = pool.splitPool(ipAddress);
432 newList.addAll(pools);
438 allocationPools = newList;
442 * release an IP address back to the subnet. Although an iterator
443 * is used, the list is not modified until the iterator is complete, so
444 * an extra list is not necessary.
446 public void releaseIP(String ipAddress) {
447 NeutronSubnet_IPAllocationPool lPool = null;
448 NeutronSubnet_IPAllocationPool hPool = null;
449 Iterator<NeutronSubnet_IPAllocationPool> i = allocationPools.iterator();
450 long sIP = NeutronSubnet_IPAllocationPool.convert(ipAddress);
451 //look for lPool where ipAddr - 1 is high address
452 //look for hPool where ipAddr + 1 is low address
453 while (i.hasNext()) {
454 NeutronSubnet_IPAllocationPool pool = i.next();
455 long lIP = NeutronSubnet_IPAllocationPool.convert(pool.getPoolStart());
456 long hIP = NeutronSubnet_IPAllocationPool.convert(pool.getPoolEnd());
464 //if (lPool == NULL and hPool == NULL) create new pool where low = ip = high
465 if (lPool == null && hPool == null) {
466 allocationPools.add(new NeutronSubnet_IPAllocationPool(ipAddress,ipAddress));
468 //if (lPool == NULL and hPool != NULL) change low address of hPool to ipAddr
469 if (lPool == null && hPool != null) {
470 hPool.setPoolStart(ipAddress);
472 //if (lPool != NULL and hPool == NULL) change high address of lPool to ipAddr
473 if (lPool != null && hPool == null) {
474 lPool.setPoolEnd(ipAddress);
476 //if (lPool != NULL and hPool != NULL) remove lPool and hPool and create new pool
477 // where low address = lPool.low address and high address = hPool.high Address
478 if (lPool != null && hPool != null) {
479 allocationPools.remove(lPool);
480 allocationPools.remove(hPool);
481 allocationPools.add(new NeutronSubnet_IPAllocationPool(
482 lPool.getPoolStart(), hPool.getPoolEnd()));
486 public void setGatewayIPAllocated() {
487 gatewayIPAssigned = true;
490 public void resetGatewayIPAllocated() {
491 gatewayIPAssigned = false;
494 public Boolean getGatewayIPAllocated() {
495 return gatewayIPAssigned;
499 public String toString() {
500 return "NeutronSubnet [subnetUUID=" + subnetUUID + ", networkUUID=" + networkUUID + ", name=" + name
501 + ", ipVersion=" + ipVersion + ", cidr=" + cidr + ", gatewayIP=" + gatewayIP + ", dnsNameservers="
502 + dnsNameservers + ", allocationPools=" + allocationPools + ", hostRoutes=" + hostRoutes
503 + ", enableDHCP=" + enableDHCP + ", tenantID=" + tenantID + ", myPorts=" + myPorts
504 + ", gatewayIPAssigned=" + gatewayIPAssigned + ", ipv6AddressMode=" + ipV6AddressMode
505 + ", ipv6RaMode=" + ipV6RaMode + "]";