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