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