add -Xlint:unchecked and -Xlint:deprecation to compiler argument
[neutron.git] / neutron-spi / src / main / java / org / opendaylight / neutron / spi / NeutronSubnet.java
1 /*
2  * Copyright (c) 2013, 2015 IBM Corporation and others.  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.neutron.spi;
10
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;
19
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;
24
25 import org.apache.commons.net.util.SubnetUtils;
26 import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
27
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 @XmlRootElement
32 @XmlAccessorType(XmlAccessType.NONE)
33
34 public class NeutronSubnet extends NeutronObject implements Serializable, INeutronObject {
35     private static final Logger LOGGER = LoggerFactory
36             .getLogger(NeutronCRUDInterfaces.class);
37
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;
45
46     // See OpenStack Network API v2.0 Reference for description of
47     // annotated attributes
48
49     @XmlElement (name = "network_id")
50     String networkUUID;
51
52     @XmlElement (name = "name")
53     String name;
54
55     @XmlElement (defaultValue = "4", name = "ip_version")
56     Integer ipVersion;
57
58     @XmlElement (name = "cidr")
59     String cidr;
60
61     @XmlElement (name = "gateway_ip")
62     String gatewayIP;
63
64     @XmlElement (name = "dns_nameservers")
65     List<String> dnsNameservers;
66
67     @XmlElement (name = "allocation_pools")
68     List<NeutronSubnetIPAllocationPool> allocationPools;
69
70     @XmlElement (name = "host_routes")
71     List<NeutronRoute> hostRoutes;
72
73     @XmlElement (defaultValue = "true", name = "enable_dhcp")
74     Boolean enableDHCP;
75
76     @XmlElement (name = "ipv6_address_mode", nillable = true)
77     String ipV6AddressMode;
78
79     @XmlElement (name = "ipv6_ra_mode", nillable = true)
80     String ipV6RaMode;
81
82     public String getNetworkUUID() {
83         return networkUUID;
84     }
85
86     public void setNetworkUUID(String networkUUID) {
87         this.networkUUID = networkUUID;
88     }
89
90     public String getName() {
91         return name;
92     }
93
94     public void setName(String name) {
95         this.name = name;
96     }
97
98     public Integer getIpVersion() {
99         return ipVersion;
100     }
101
102     public void setIpVersion(Integer ipVersion) {
103         this.ipVersion = ipVersion;
104     }
105
106     public String getCidr() {
107         return cidr;
108     }
109
110     public void setCidr(String cidr) {
111         this.cidr = cidr;
112     }
113
114     public String getGatewayIP() {
115         return gatewayIP;
116     }
117
118     public void setGatewayIP(String gatewayIP) {
119         this.gatewayIP = gatewayIP;
120     }
121
122     public List<String> getDnsNameservers() {
123         return dnsNameservers;
124     }
125
126     public void setDnsNameservers(List<String> dnsNameservers) {
127         this.dnsNameservers = dnsNameservers;
128     }
129
130     public List<NeutronSubnetIPAllocationPool> getAllocationPools() {
131         return allocationPools;
132     }
133
134     public void setAllocationPools(List<NeutronSubnetIPAllocationPool> allocationPools) {
135         this.allocationPools = allocationPools;
136     }
137
138     public List<NeutronRoute> getHostRoutes() {
139         return hostRoutes;
140     }
141
142     public void setHostRoutes(List<NeutronRoute> hostRoutes) {
143         this.hostRoutes = hostRoutes;
144     }
145
146     public boolean isEnableDHCP() {
147         if (enableDHCP == null) {
148             return true;
149         }
150         return enableDHCP;
151     }
152
153     public Boolean getEnableDHCP() { return enableDHCP; }
154
155     public void setEnableDHCP(Boolean newValue) {
156             enableDHCP = newValue;
157     }
158
159     public String getIpV6AddressMode() { return ipV6AddressMode; }
160
161     public void setIpV6AddressMode(String ipV6AddressMode) { this.ipV6AddressMode = ipV6AddressMode; }
162
163     public String getIpV6RaMode() { return ipV6RaMode; }
164
165     public void setIpV6RaMode(String ipV6RaMode) { this.ipV6RaMode = ipV6RaMode; }
166
167     /**
168      * This method copies selected fields from the object and returns them
169      * as a new object, suitable for marshaling.
170      *
171      * @param fields
172      *            List of attributes to be extracted
173      * @return an OpenStackSubnets object with only the selected fields
174      * populated
175      */
176
177     public NeutronSubnet extractFields(List<String> fields) {
178         NeutronSubnet ans = new NeutronSubnet();
179         Iterator<String> i = fields.iterator();
180         while (i.hasNext()) {
181             String s = i.next();
182             if (s.equals("id")) {
183                 ans.setID(this.getID());
184             }
185             if (s.equals("network_id")) {
186                 ans.setNetworkUUID(this.getNetworkUUID());
187             }
188             if (s.equals("name")) {
189                 ans.setName(this.getName());
190             }
191             if (s.equals("ip_version")) {
192                 ans.setIpVersion(this.getIpVersion());
193             }
194             if (s.equals("cidr")) {
195                 ans.setCidr(this.getCidr());
196             }
197             if (s.equals("gateway_ip")) {
198                 ans.setGatewayIP(this.getGatewayIP());
199             }
200             if (s.equals("dns_nameservers")) {
201                 List<String> nsList = new ArrayList<String>();
202                 nsList.addAll(this.getDnsNameservers());
203                 ans.setDnsNameservers(nsList);
204             }
205             if (s.equals("allocation_pools")) {
206                 List<NeutronSubnetIPAllocationPool> aPools = new ArrayList<NeutronSubnetIPAllocationPool>();
207                 aPools.addAll(this.getAllocationPools());
208                 ans.setAllocationPools(aPools);
209             }
210             if (s.equals("host_routes")) {
211                 List<NeutronRoute> hRoutes = new ArrayList<NeutronRoute>();
212                 hRoutes.addAll(this.getHostRoutes());
213                 ans.setHostRoutes(hRoutes);
214             }
215             if (s.equals("enable_dhcp")) {
216                 ans.setEnableDHCP(this.getEnableDHCP());
217             }
218             if (s.equals("tenant_id")) {
219                 ans.setTenantID(this.getTenantID());
220             }
221             if (s.equals("ipv6_address_mode")) {
222                 ans.setIpV6AddressMode(this.getIpV6AddressMode());
223             }
224             if (s.equals("ipv6_ra_mode")) {
225                 ans.setIpV6RaMode(this.getIpV6RaMode());
226             }
227         }
228         return ans;
229     }
230
231     /* test to see if the cidr address used to define this subnet
232      * is a valid network address (an necessary condition when creating
233      * a new subnet)
234      */
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) {
239             try {
240                 SubnetUtils util = new SubnetUtils(cidr);
241                 SubnetInfo info = util.getInfo();
242                 if (!info.getNetworkAddress().equals(info.getAddress())) {
243                     return false;
244                 }
245             } catch (IllegalArgumentException e) {
246                 LOGGER.warn("Failure in isValidCIDR()", e);
247                 return false;
248             }
249             return true;
250         }
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) {
257                 return false;
258             }
259             try {
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();
264                 int i;
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) {
267                         return(false);
268                     }
269                 }
270                 return(true);
271             } catch (UnknownHostException e) {
272                 LOGGER.warn("Failure in isValidCIDR()", e);
273                 return(false);
274             }
275         }
276         return false;
277     }
278
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)
282      */
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)) {
288                 return true;
289             }
290             if (ipVersion == IPV6_VERSION && pool.containsV6(gatewayIP)) {
291                 return true;
292             }
293         }
294         return false;
295     }
296
297     @Override
298     public void initDefaults() {
299         if (enableDHCP == null) {
300             enableDHCP = true;
301         }
302         if (ipVersion == null) {
303             ipVersion = IPV4_VERSION;
304         }
305         if (dnsNameservers == null) {
306             dnsNameservers = new ArrayList<String>();
307         }
308         if (hostRoutes == null) {
309             hostRoutes = new ArrayList<NeutronRoute>();
310         }
311         if (allocationPools == null) {
312             allocationPools = new ArrayList<NeutronSubnetIPAllocationPool>();
313             if (ipVersion == IPV4_VERSION) {
314                 try {
315                     SubnetUtils util = new SubnetUtils(cidr);
316                     SubnetInfo info = util.getInfo();
317                     if (gatewayIP == null || ("").equals(gatewayIP)) {
318                         gatewayIP = info.getLowAddress();
319                     }
320                     if (allocationPools.size() < 1) {
321                         NeutronSubnetIPAllocationPool source =
322                             new NeutronSubnetIPAllocationPool(info.getLowAddress(),
323                                     info.getHighAddress());
324                         allocationPools = source.splitPool(gatewayIP);
325                     }
326                 } catch (IllegalArgumentException e) {
327                     LOGGER.warn("Failure in initDefault()", e);
328                     return;
329                 }
330             }
331             if (ipVersion == IPV6_VERSION) {
332                 String[] parts = cidr.split("/");
333                 if (parts.length != 2) {
334                     return;
335                 }
336                 try {
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;
344                     }
345                     if (allocationPools.size() < 1) {
346                         NeutronSubnetIPAllocationPool source =
347                             new NeutronSubnetIPAllocationPool(lowAddress,
348                                     highAddress);
349                         allocationPools = source.splitPoolV6(gatewayIP);
350                     }
351                 } catch (Exception e) {
352                     LOGGER.warn("Failure in initDefault()", e);
353                     return;
354                 }
355             }
356         }
357     }
358
359     /* this method tests to see if the supplied IPv4 address
360      * is valid for this subnet or not
361      */
362     public boolean isValidIP(String ipAddress) {
363         if (ipVersion == IPV4_VERSION) {
364             try {
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);
370                 return false;
371             }
372         }
373
374         if (ipVersion == IPV6_VERSION) {
375             String[] parts = cidr.split("/");
376             try {
377                 int length = Integer.parseInt(parts[1]);
378                 byte[] cidrBytes = ((Inet6Address) InetAddress.getByName(parts[0])).getAddress();
379                 byte[] ipBytes =  ((Inet6Address) InetAddress.getByName(ipAddress)).getAddress();
380                 int i;
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))))) {
384                         return(false);
385                     }
386                 }
387                 return(true);
388             } catch (UnknownHostException e) {
389                 LOGGER.warn("Failure in isValidIP()", e);
390                 return(false);
391             }
392         }
393         return false;
394     }
395
396     /* method to get the lowest available address of the subnet.
397      * go through all the allocation pools and keep the lowest of their
398      * low addresses.
399      */
400     public String getLowAddr() {
401         String ans = null;
402         Iterator<NeutronSubnetIPAllocationPool> i = allocationPools.iterator();
403         while (i.hasNext()) {
404             NeutronSubnetIPAllocationPool pool = i.next();
405             if (ans == null) {
406                 ans = pool.getPoolStart();
407             }
408             else {
409                 if (ipVersion == IPV4_VERSION &&
410                     NeutronSubnetIPAllocationPool.convert(pool.getPoolStart()) <
411                             NeutronSubnetIPAllocationPool.convert(ans)) {
412                     ans = pool.getPoolStart();
413                 }
414                 if (ipVersion == IPV6_VERSION &&
415                     NeutronSubnetIPAllocationPool.convertV6(pool.getPoolStart()).compareTo(NeutronSubnetIPAllocationPool.convertV6(ans)) < 0) {
416                     ans = pool.getPoolStart();
417                 }
418            }
419         }
420         return ans;
421     }
422
423     @Override
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 + "]";
431     }
432 }