Merge "Complete implementation of DataChangeListenerProxy"
[controller.git] / opendaylight / networkconfiguration / neutron / src / main / java / org / opendaylight / controller / networkconfig / neutron / NeutronSubnet.java
1 /*
2  * Copyright IBM Corporation and others, 2013.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.controller.networkconfig.neutron;
10
11 import java.io.Serializable;
12 import java.util.ArrayList;
13 import java.util.Iterator;
14 import java.util.List;
15
16 import javax.xml.bind.annotation.XmlAccessType;
17 import javax.xml.bind.annotation.XmlAccessorType;
18 import javax.xml.bind.annotation.XmlElement;
19 import javax.xml.bind.annotation.XmlRootElement;
20
21 import org.apache.commons.net.util.SubnetUtils;
22 import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
23 import org.opendaylight.controller.configuration.ConfigurationObject;
24
25 @XmlRootElement
26 @XmlAccessorType(XmlAccessType.NONE)
27
28 public class NeutronSubnet extends ConfigurationObject implements Serializable, INeutronObject {
29     private static final long serialVersionUID = 1L;
30
31     // See OpenStack Network API v2.0 Reference for description of
32     // annotated attributes
33
34     @XmlElement (name="id")
35     String subnetUUID;
36
37     @XmlElement (name="network_id")
38     String networkUUID;
39
40     @XmlElement (name="name")
41     String name;
42
43     @XmlElement (defaultValue="4", name="ip_version")
44     Integer ipVersion;
45
46     @XmlElement (name="cidr")
47     String cidr;
48
49     @XmlElement (name="gateway_ip")
50     String gatewayIP;
51
52     @XmlElement (name="dns_nameservers")
53     List<String> dnsNameservers;
54
55     @XmlElement (name="allocation_pools")
56     List<NeutronSubnet_IPAllocationPool> allocationPools;
57
58     @XmlElement (name="host_routes")
59     List<NeutronSubnet_HostRoute> hostRoutes;
60
61     @XmlElement (defaultValue="true", name="enable_dhcp")
62     Boolean enableDHCP;
63
64     @XmlElement (name="tenant_id")
65     String tenantID;
66
67     @XmlElement (name="ipv6_address_mode", nillable=true)
68     String ipV6AddressMode;
69
70     @XmlElement (name="ipv6_ra_mode", nillable=true)
71     String ipV6RaMode;
72
73     /* stores the OpenStackPorts associated with an instance
74      * used to determine if that instance can be deleted.
75      */
76     List<NeutronPort> myPorts;
77
78     boolean gatewayIPAssigned;
79
80     public NeutronSubnet() {
81         myPorts = new ArrayList<NeutronPort>();
82     }
83
84     public String getID() { return subnetUUID; }
85
86     public void setID(String id) { this.subnetUUID = id; }
87
88     public String getSubnetUUID() {
89         return subnetUUID;
90     }
91
92     public void setSubnetUUID(String subnetUUID) {
93         this.subnetUUID = subnetUUID;
94     }
95
96     public String getNetworkUUID() {
97         return networkUUID;
98     }
99
100     public void setNetworkUUID(String networkUUID) {
101         this.networkUUID = networkUUID;
102     }
103
104     public String getName() {
105         return name;
106     }
107
108     public void setName(String name) {
109         this.name = name;
110     }
111
112     public Integer getIpVersion() {
113         return ipVersion;
114     }
115
116     public void setIpVersion(Integer ipVersion) {
117         this.ipVersion = ipVersion;
118     }
119
120     public String getCidr() {
121         return cidr;
122     }
123
124     public void setCidr(String cidr) {
125         this.cidr = cidr;
126     }
127
128     public String getGatewayIP() {
129         return gatewayIP;
130     }
131
132     public void setGatewayIP(String gatewayIP) {
133         this.gatewayIP = gatewayIP;
134     }
135
136     public List<String> getDnsNameservers() {
137         return dnsNameservers;
138     }
139
140     public void setDnsNameservers(List<String> dnsNameservers) {
141         this.dnsNameservers = dnsNameservers;
142     }
143
144     public List<NeutronSubnet_IPAllocationPool> getAllocationPools() {
145         return allocationPools;
146     }
147
148     public void setAllocationPools(List<NeutronSubnet_IPAllocationPool> allocationPools) {
149         this.allocationPools = allocationPools;
150     }
151
152     public List<NeutronSubnet_HostRoute> getHostRoutes() {
153         return hostRoutes;
154     }
155
156     public void setHostRoutes(List<NeutronSubnet_HostRoute> hostRoutes) {
157         this.hostRoutes = hostRoutes;
158     }
159
160     public boolean isEnableDHCP() {
161         if (enableDHCP == null) {
162             return true;
163         }
164         return enableDHCP;
165     }
166
167     public Boolean getEnableDHCP() { return enableDHCP; }
168
169     public void setEnableDHCP(Boolean newValue) {
170             enableDHCP = newValue;
171     }
172
173     public String getTenantID() {
174         return tenantID;
175     }
176
177     public void setTenantID(String tenantID) {
178         this.tenantID = tenantID;
179     }
180
181     public String getIpV6AddressMode() { return ipV6AddressMode; }
182
183     public void setIpV6AddressMode(String ipV6AddressMode) { this.ipV6AddressMode = ipV6AddressMode; }
184
185     public String getIpV6RaMode() { return ipV6RaMode; }
186
187     public void setIpV6RaMode(String ipV6RaMode) { this.ipV6RaMode = ipV6RaMode; }
188
189     /**
190      * This method copies selected fields from the object and returns them
191      * as a new object, suitable for marshaling.
192      *
193      * @param fields
194      *            List of attributes to be extracted
195      * @return an OpenStackSubnets object with only the selected fields
196      * populated
197      */
198
199     public NeutronSubnet extractFields(List<String> fields) {
200         NeutronSubnet ans = new NeutronSubnet();
201         Iterator<String> i = fields.iterator();
202         while (i.hasNext()) {
203             String s = i.next();
204             if (s.equals("id")) {
205                 ans.setSubnetUUID(this.getSubnetUUID());
206             }
207             if (s.equals("network_id")) {
208                 ans.setNetworkUUID(this.getNetworkUUID());
209             }
210             if (s.equals("name")) {
211                 ans.setName(this.getName());
212             }
213             if (s.equals("ip_version")) {
214                 ans.setIpVersion(this.getIpVersion());
215             }
216             if (s.equals("cidr")) {
217                 ans.setCidr(this.getCidr());
218             }
219             if (s.equals("gateway_ip")) {
220                 ans.setGatewayIP(this.getGatewayIP());
221             }
222             if (s.equals("dns_nameservers")) {
223                 List<String> nsList = new ArrayList<String>();
224                 nsList.addAll(this.getDnsNameservers());
225                 ans.setDnsNameservers(nsList);
226             }
227             if (s.equals("allocation_pools")) {
228                 List<NeutronSubnet_IPAllocationPool> aPools = new ArrayList<NeutronSubnet_IPAllocationPool>();
229                 aPools.addAll(this.getAllocationPools());
230                 ans.setAllocationPools(aPools);
231             }
232             if (s.equals("host_routes")) {
233                 List<NeutronSubnet_HostRoute> hRoutes = new ArrayList<NeutronSubnet_HostRoute>();
234                 hRoutes.addAll(this.getHostRoutes());
235                 ans.setHostRoutes(hRoutes);
236             }
237             if (s.equals("enable_dhcp")) {
238                 ans.setEnableDHCP(this.getEnableDHCP());
239             }
240             if (s.equals("tenant_id")) {
241                 ans.setTenantID(this.getTenantID());
242             }
243             if (s.equals("ipv6_address_mode")) {
244                 ans.setIpV6AddressMode(this.getIpV6AddressMode());
245             }
246             if (s.equals("ipv6_ra_mode")) {
247                 ans.setIpV6RaMode(this.getIpV6RaMode());
248             }
249         }
250         return ans;
251     }
252
253     /* test to see if the cidr address used to define this subnet
254      * is a valid network address (an necessary condition when creating
255      * a new subnet)
256      */
257     public boolean isValidCIDR() {
258         try {
259             SubnetUtils util = new SubnetUtils(cidr);
260             SubnetInfo info = util.getInfo();
261             if (!info.getNetworkAddress().equals(info.getAddress())) {
262                 return false;
263             }
264         } catch (Exception e) {
265             return false;
266         }
267         return true;
268     }
269
270     /* test to see if the gateway IP specified overlaps with specified
271      * allocation pools (an error condition when creating a new subnet
272      * or assigning a gateway IP)
273      */
274     public boolean gatewayIP_Pool_overlap() {
275         Iterator<NeutronSubnet_IPAllocationPool> i = allocationPools.iterator();
276         while (i.hasNext()) {
277             NeutronSubnet_IPAllocationPool pool = i.next();
278             if (pool.contains(gatewayIP)) {
279                 return true;
280             }
281         }
282         return false;
283     }
284
285     public boolean initDefaults() {
286         if (enableDHCP == null) {
287             enableDHCP = true;
288         }
289         if (ipVersion == null) {
290             ipVersion = 4;
291         }
292         gatewayIPAssigned = false;
293         dnsNameservers = new ArrayList<String>();
294         if (hostRoutes == null) {
295             hostRoutes = new ArrayList<NeutronSubnet_HostRoute>();
296         }
297         if (allocationPools == null) {
298             allocationPools = new ArrayList<NeutronSubnet_IPAllocationPool>();
299             try {
300                 SubnetUtils util = new SubnetUtils(cidr);
301                 SubnetInfo info = util.getInfo();
302                 if (gatewayIP == null) {
303                     gatewayIP = info.getLowAddress();
304                 }
305                 if (allocationPools.size() < 1) {
306                     NeutronSubnet_IPAllocationPool source =
307                         new NeutronSubnet_IPAllocationPool(info.getLowAddress(),
308                                 info.getHighAddress());
309                     allocationPools = source.splitPool(gatewayIP);
310                 }
311             } catch (Exception e) {
312                 return false;
313             }
314         }
315         return true;
316     }
317
318     public List<NeutronPort> getPortsInSubnet() {
319         return myPorts;
320     }
321
322     public void addPort(NeutronPort port) {
323         myPorts.add(port);
324     }
325
326     public void removePort(NeutronPort port) {
327         myPorts.remove(port);
328     }
329
330     /* this method tests to see if the supplied IPv4 address
331      * is valid for this subnet or not
332      */
333     public boolean isValidIP(String ipAddress) {
334         try {
335             SubnetUtils util = new SubnetUtils(cidr);
336             SubnetInfo info = util.getInfo();
337             return info.isInRange(ipAddress);
338         } catch (Exception e) {
339             return false;
340         }
341     }
342
343     /* test to see if the supplied IPv4 address is part of one of the
344      * available allocation pools or not
345      */
346     public boolean isIPInUse(String ipAddress) {
347         if (ipAddress.equals(gatewayIP) && !gatewayIPAssigned ) {
348             return false;
349         }
350         Iterator<NeutronSubnet_IPAllocationPool> i = allocationPools.iterator();
351         while (i.hasNext()) {
352             NeutronSubnet_IPAllocationPool pool = i.next();
353             if (pool.contains(ipAddress)) {
354                 return false;
355             }
356         }
357         return true;
358     }
359
360     /* method to get the lowest available address of the subnet.
361      * go through all the allocation pools and keep the lowest of their
362      * low addresses.
363      */
364     public String getLowAddr() {
365         String ans = null;
366         Iterator<NeutronSubnet_IPAllocationPool> i = allocationPools.iterator();
367         while (i.hasNext()) {
368             NeutronSubnet_IPAllocationPool pool = i.next();
369             if (ans == null) {
370                 ans = pool.getPoolStart();
371             }
372             else
373                 if (NeutronSubnet_IPAllocationPool.convert(pool.getPoolStart()) <
374                         NeutronSubnet_IPAllocationPool.convert(ans)) {
375                     ans = pool.getPoolStart();
376                 }
377         }
378         return ans;
379     }
380
381     /*
382      * allocate the parameter address.  Because this uses an iterator to
383      * check the instance's list of allocation pools and we want to modify
384      * pools while the iterator is being used, it is necessary to
385      * build a new list of allocation pools and replace the list when
386      * finished (otherwise a split will cause undefined iterator behavior.
387      */
388     public void allocateIP(String ipAddress) {
389         Iterator<NeutronSubnet_IPAllocationPool> i = allocationPools.iterator();
390         List<NeutronSubnet_IPAllocationPool> newList = new ArrayList<NeutronSubnet_IPAllocationPool>();    // we have to modify a separate list
391         while (i.hasNext()) {
392             NeutronSubnet_IPAllocationPool pool = i.next();
393             /* if the pool contains a single address element and we are allocating it
394              * then we don't need to copy the pool over.  Otherwise, we need to possibly
395              * split the pool and add both pieces to the new list
396              */
397             if (!(pool.getPoolEnd().equalsIgnoreCase(ipAddress) &&
398                     pool.getPoolStart().equalsIgnoreCase(ipAddress))) {
399                 if (pool.contains(ipAddress)) {
400                     List<NeutronSubnet_IPAllocationPool> pools = pool.splitPool(ipAddress);
401                     newList.addAll(pools);
402                 } else {
403                     newList.add(pool);
404                 }
405             }
406         }
407         allocationPools = newList;
408     }
409
410     /*
411      * release an IP address back to the subnet.  Although an iterator
412      * is used, the list is not modified until the iterator is complete, so
413      * an extra list is not necessary.
414      */
415     public void releaseIP(String ipAddress) {
416         NeutronSubnet_IPAllocationPool lPool = null;
417         NeutronSubnet_IPAllocationPool hPool = null;
418         Iterator<NeutronSubnet_IPAllocationPool> i = allocationPools.iterator();
419         long sIP = NeutronSubnet_IPAllocationPool.convert(ipAddress);
420         //look for lPool where ipAddr - 1 is high address
421         //look for hPool where ipAddr + 1 is low address
422         while (i.hasNext()) {
423             NeutronSubnet_IPAllocationPool pool = i.next();
424             long lIP = NeutronSubnet_IPAllocationPool.convert(pool.getPoolStart());
425             long hIP = NeutronSubnet_IPAllocationPool.convert(pool.getPoolEnd());
426             if (sIP+1 == lIP) {
427                 hPool = pool;
428             }
429             if (sIP-1 == hIP) {
430                 lPool = pool;
431             }
432         }
433         //if (lPool == NULL and hPool == NULL) create new pool where low = ip = high
434         if (lPool == null && hPool == null) {
435             allocationPools.add(new NeutronSubnet_IPAllocationPool(ipAddress,ipAddress));
436         }
437         //if (lPool == NULL and hPool != NULL) change low address of hPool to ipAddr
438         if (lPool == null && hPool != null) {
439             hPool.setPoolStart(ipAddress);
440         }
441         //if (lPool != NULL and hPool == NULL) change high address of lPool to ipAddr
442         if (lPool != null && hPool == null) {
443             lPool.setPoolEnd(ipAddress);
444         }
445         //if (lPool != NULL and hPool != NULL) remove lPool and hPool and create new pool
446         //        where low address = lPool.low address and high address = hPool.high Address
447         if (lPool != null && hPool != null) {
448             allocationPools.remove(lPool);
449             allocationPools.remove(hPool);
450             allocationPools.add(new NeutronSubnet_IPAllocationPool(
451                     lPool.getPoolStart(), hPool.getPoolEnd()));
452         }
453     }
454
455     public void setGatewayIPAllocated() {
456         gatewayIPAssigned = true;
457     }
458
459     public void resetGatewayIPAllocated() {
460         gatewayIPAssigned = false;
461     }
462
463     @Override
464     public String toString() {
465         return "NeutronSubnet [subnetUUID=" + subnetUUID + ", networkUUID=" + networkUUID + ", name=" + name
466                 + ", ipVersion=" + ipVersion + ", cidr=" + cidr + ", gatewayIP=" + gatewayIP + ", dnsNameservers="
467                 + dnsNameservers + ", allocationPools=" + allocationPools + ", hostRoutes=" + hostRoutes
468                 + ", enableDHCP=" + enableDHCP + ", tenantID=" + tenantID + ", myPorts=" + myPorts
469                 + ", gatewayIPAssigned=" + gatewayIPAssigned + ", ipv6AddressMode=" + ipV6AddressMode
470                 + ", ipv6RaMode=" + ipV6RaMode + "]";
471     }
472 }