Merge "Maven cleanup and features-parent migration"
[ovsdb.git] / openstack / net-virt / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / translator / 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.ovsdb.openstack.netvirt.translator;
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 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.NeutronCRUDInterfaces;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 @XmlRootElement
32 @XmlAccessorType(XmlAccessType.NONE)
33
34 public class NeutronSubnet 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 = "id")
50     String subnetUUID;
51
52     @XmlElement (name = "network_id")
53     String networkUUID;
54
55     @XmlElement (name = "name")
56     String name;
57
58     @XmlElement (defaultValue = "4", name = "ip_version")
59     Integer ipVersion;
60
61     @XmlElement (name = "cidr")
62     String cidr;
63
64     @XmlElement (name = "gateway_ip")
65     String gatewayIP;
66
67     @XmlElement (name = "dns_nameservers")
68     List<String> dnsNameservers;
69
70     @XmlElement (name = "allocation_pools")
71     List<NeutronSubnetIPAllocationPool> allocationPools;
72
73     @XmlElement (name = "host_routes")
74     List<NeutronSubnet_HostRoute> hostRoutes;
75
76     @XmlElement (defaultValue = "true", name = "enable_dhcp")
77     Boolean enableDHCP;
78
79     @XmlElement (name = "tenant_id")
80     String tenantID;
81
82     @XmlElement (name = "ipv6_address_mode", nillable = true)
83     String ipV6AddressMode;
84
85     @XmlElement (name = "ipv6_ra_mode", nillable = true)
86     String ipV6RaMode;
87
88     /* stores the OpenStackPorts associated with an instance
89      * used to determine if that instance can be deleted.
90      *
91      * @deprecated, will be removed in Boron
92      */
93
94     List<NeutronPort> myPorts;
95
96     public NeutronSubnet() {
97         myPorts = new ArrayList<>();
98     }
99
100     // @deprecated - will be removed in Boron
101     public void setPorts(List<NeutronPort> arg) {
102         myPorts = arg;
103     }
104
105     public String getID() { return subnetUUID; }
106
107     public void setID(String id) { this.subnetUUID = id; }
108
109     public String getSubnetUUID() {
110         return subnetUUID;
111     }
112
113     public void setSubnetUUID(String subnetUUID) {
114         this.subnetUUID = subnetUUID;
115     }
116
117     public String getNetworkUUID() {
118         return networkUUID;
119     }
120
121     public void setNetworkUUID(String networkUUID) {
122         this.networkUUID = networkUUID;
123     }
124
125     public String getName() {
126         return name;
127     }
128
129     public void setName(String name) {
130         this.name = name;
131     }
132
133     public Integer getIpVersion() {
134         return ipVersion;
135     }
136
137     public void setIpVersion(Integer ipVersion) {
138         this.ipVersion = ipVersion;
139     }
140
141     public String getCidr() {
142         return cidr;
143     }
144
145     public void setCidr(String cidr) {
146         this.cidr = cidr;
147     }
148
149     public String getGatewayIP() {
150         return gatewayIP;
151     }
152
153     public void setGatewayIP(String gatewayIP) {
154         this.gatewayIP = gatewayIP;
155     }
156
157     public List<String> getDnsNameservers() {
158         return dnsNameservers;
159     }
160
161     public void setDnsNameservers(List<String> dnsNameservers) {
162         this.dnsNameservers = dnsNameservers;
163     }
164
165     public List<NeutronSubnetIPAllocationPool> getAllocationPools() {
166         return allocationPools;
167     }
168
169     public void setAllocationPools(List<NeutronSubnetIPAllocationPool> allocationPools) {
170         this.allocationPools = allocationPools;
171     }
172
173     public List<NeutronSubnet_HostRoute> getHostRoutes() {
174         return hostRoutes;
175     }
176
177     public void setHostRoutes(List<NeutronSubnet_HostRoute> hostRoutes) {
178         this.hostRoutes = hostRoutes;
179     }
180
181     public boolean isEnableDHCP() {
182         if (enableDHCP == null) {
183             return true;
184         }
185         return enableDHCP;
186     }
187
188     public Boolean getEnableDHCP() { return enableDHCP; }
189
190     public void setEnableDHCP(Boolean newValue) {
191             enableDHCP = newValue;
192     }
193
194     public String getTenantID() {
195         return tenantID;
196     }
197
198     public void setTenantID(String tenantID) {
199         this.tenantID = tenantID;
200     }
201
202     public String getIpV6AddressMode() { return ipV6AddressMode; }
203
204     public void setIpV6AddressMode(String ipV6AddressMode) { this.ipV6AddressMode = ipV6AddressMode; }
205
206     public String getIpV6RaMode() { return ipV6RaMode; }
207
208     public void setIpV6RaMode(String ipV6RaMode) { this.ipV6RaMode = ipV6RaMode; }
209
210     /**
211      * This method copies selected fields from the object and returns them
212      * as a new object, suitable for marshaling.
213      *
214      * @param fields
215      *            List of attributes to be extracted
216      * @return an OpenStackSubnets object with only the selected fields
217      * populated
218      */
219
220     public NeutronSubnet extractFields(List<String> fields) {
221         NeutronSubnet ans = new NeutronSubnet();
222         for (String s : fields) {
223             switch (s) {
224                 case "id":
225                     ans.setSubnetUUID(this.getSubnetUUID());
226                     break;
227                 case "network_id":
228                     ans.setNetworkUUID(this.getNetworkUUID());
229                     break;
230                 case "name":
231                     ans.setName(this.getName());
232                     break;
233                 case "ip_version":
234                     ans.setIpVersion(this.getIpVersion());
235                     break;
236                 case "cidr":
237                     ans.setCidr(this.getCidr());
238                     break;
239                 case "gateway_ip":
240                     ans.setGatewayIP(this.getGatewayIP());
241                     break;
242                 case "dns_nameservers":
243                     List<String> nsList = new ArrayList<>();
244                     nsList.addAll(this.getDnsNameservers());
245                     ans.setDnsNameservers(nsList);
246                     break;
247                 case "allocation_pools":
248                     List<NeutronSubnetIPAllocationPool> aPools = new ArrayList<>();
249                     aPools.addAll(this.getAllocationPools());
250                     ans.setAllocationPools(aPools);
251                     break;
252                 case "host_routes":
253                     List<NeutronSubnet_HostRoute> hRoutes = new ArrayList<>();
254                     hRoutes.addAll(this.getHostRoutes());
255                     ans.setHostRoutes(hRoutes);
256                     break;
257                 case "enable_dhcp":
258                     ans.setEnableDHCP(this.getEnableDHCP());
259                     break;
260                 case "tenant_id":
261                     ans.setTenantID(this.getTenantID());
262                     break;
263                 case "ipv6_address_mode":
264                     ans.setIpV6AddressMode(this.getIpV6AddressMode());
265                     break;
266                 case "ipv6_ra_mode":
267                     ans.setIpV6RaMode(this.getIpV6RaMode());
268                     break;
269             }
270         }
271         return ans;
272     }
273
274     // @deprecated - will be removed in Boron
275     public List<NeutronPort> getPortsInSubnet() {
276         return myPorts;
277     }
278
279     // @deprecated - will be removed in Boron
280     public List<NeutronPort> getPortsInSubnet(String ignore) {
281        List<NeutronPort> answer = new ArrayList<>();
282        for (NeutronPort port : myPorts) {
283            if (!port.getDeviceOwner().equalsIgnoreCase(ignore)) {
284                 answer.add(port);
285             }
286         }
287         return answer;
288     }
289
290     /* test to see if the cidr address used to define this subnet
291      * is a valid network address (an necessary condition when creating
292      * a new subnet)
293      */
294     public boolean isValidCIDR() {
295         // fix for Bug 2290 - need to wrap the existing test as
296         // IPv4 because SubnetUtils doesn't support IPv6
297         if (ipVersion == IPV4_VERSION) {
298             try {
299                 SubnetUtils util = new SubnetUtils(cidr);
300                 SubnetInfo info = util.getInfo();
301                 if (!info.getNetworkAddress().equals(info.getAddress())) {
302                     return false;
303                 }
304             } catch (IllegalArgumentException e) {
305                 LOGGER.warn("Failure in isValidCIDR()", e);
306                 return false;
307             }
308             return true;
309         }
310         if (ipVersion == IPV6_VERSION) {
311             // fix for Bug2290 - this is custom code because no classes
312             // with ODL-friendly licenses have been found
313             // extract address (in front of /) and length (after /)
314             String[] parts = cidr.split("/");
315             if (parts.length != 2) {
316                 return false;
317             }
318             try {
319                 int length = Integer.parseInt(parts[1]);
320                 //TODO?: limit check on length
321                 // convert to byte array
322                 byte[] addrBytes = InetAddress.getByName(parts[0]).getAddress();
323                 int i;
324                 for (i = length; i < IPV6_LENGTH; i++) {
325                     if (((((int) addrBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES)))) != 0) {
326                         return(false);
327                     }
328                 }
329                 return(true);
330             } catch (UnknownHostException e) {
331                 LOGGER.warn("Failure in isValidCIDR()", e);
332                 return(false);
333             }
334         }
335         return false;
336     }
337
338     /* test to see if the gateway IP specified overlaps with specified
339      * allocation pools (an error condition when creating a new subnet
340      * or assigning a gateway IP)
341      */
342     public boolean gatewayIP_Pool_overlap() {
343         for (NeutronSubnetIPAllocationPool pool : allocationPools) {
344             if (ipVersion == IPV4_VERSION && pool.contains(gatewayIP)) {
345                 return true;
346             }
347             if (ipVersion == IPV6_VERSION && pool.containsV6(gatewayIP)) {
348                 return true;
349             }
350         }
351         return false;
352     }
353
354     public boolean initDefaults() {
355         if (enableDHCP == null) {
356             enableDHCP = true;
357         }
358         if (ipVersion == null) {
359             ipVersion = IPV4_VERSION;
360         }
361         dnsNameservers = new ArrayList<>();
362         if (hostRoutes == null) {
363             hostRoutes = new ArrayList<>();
364         }
365         if (allocationPools == null) {
366             allocationPools = new ArrayList<>();
367             if (ipVersion == IPV4_VERSION) {
368                 try {
369                     SubnetUtils util = new SubnetUtils(cidr);
370                     SubnetInfo info = util.getInfo();
371                     if (gatewayIP == null || ("").equals(gatewayIP)) {
372                         gatewayIP = info.getLowAddress();
373                     }
374                     if (allocationPools.size() < 1) {
375                         NeutronSubnetIPAllocationPool source =
376                             new NeutronSubnetIPAllocationPool(info.getLowAddress(),
377                                     info.getHighAddress());
378                         allocationPools = source.splitPool(gatewayIP);
379                     }
380                 } catch (IllegalArgumentException e) {
381                     LOGGER.warn("Failure in initDefault()", e);
382                     return false;
383                 }
384             }
385             if (ipVersion == IPV6_VERSION) {
386                 String[] parts = cidr.split("/");
387                 if (parts.length != 2) {
388                     return false;
389                 }
390                 try {
391                     int length = Integer.parseInt(parts[1]);
392                     BigInteger lowAddress_bi = NeutronSubnetIPAllocationPool.convertV6(parts[0]);
393                     String lowAddress = NeutronSubnetIPAllocationPool.bigIntegerToIP(lowAddress_bi.add(BigInteger.ONE));
394                     BigInteger mask = BigInteger.ONE.shiftLeft(length).subtract(BigInteger.ONE);
395                     String highAddress = NeutronSubnetIPAllocationPool.bigIntegerToIP(lowAddress_bi.add(mask).subtract(BigInteger.ONE));
396                     if (gatewayIP == null || ("").equals(gatewayIP)) {
397                         gatewayIP = lowAddress;
398                     }
399                     if (allocationPools.size() < 1) {
400                         NeutronSubnetIPAllocationPool source =
401                             new NeutronSubnetIPAllocationPool(lowAddress,
402                                     highAddress);
403                         allocationPools = source.splitPoolV6(gatewayIP);
404                     }
405                 } catch (Exception e) {
406                     LOGGER.warn("Failure in initDefault()", e);
407                     return false;
408                 }
409             }
410         }
411         return true;
412     }
413
414     /* this method tests to see if the supplied IPv4 address
415      * is valid for this subnet or not
416      */
417     public boolean isValidIP(String ipAddress) {
418         if (ipVersion == IPV4_VERSION) {
419             try {
420                 SubnetUtils util = new SubnetUtils(cidr);
421                 SubnetInfo info = util.getInfo();
422                 return info.isInRange(ipAddress);
423             } catch (IllegalArgumentException e) {
424                 LOGGER.warn("Failure in isValidIP()", e);
425                 return false;
426             }
427         }
428
429         if (ipVersion == IPV6_VERSION) {
430             String[] parts = cidr.split("/");
431             try {
432                 int length = Integer.parseInt(parts[1]);
433                 byte[] cidrBytes = InetAddress.getByName(parts[0]).getAddress();
434                 byte[] ipBytes =  InetAddress.getByName(ipAddress).getAddress();
435                 int i;
436                 for (i = 0; i < length; i++) {
437                     if (((((int) cidrBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES)))) !=
438                         ((((int) ipBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES))))) {
439                         return(false);
440                     }
441                 }
442                 return(true);
443             } catch (UnknownHostException e) {
444                 LOGGER.warn("Failure in isValidIP()", e);
445                 return(false);
446             }
447         }
448         return false;
449     }
450
451     /* method to get the lowest available address of the subnet.
452      * go through all the allocation pools and keep the lowest of their
453      * low addresses.
454      */
455     public String getLowAddr() {
456         String ans = null;
457         for (NeutronSubnetIPAllocationPool pool : allocationPools) {
458             if (ans == null) {
459                 ans = pool.getPoolStart();
460             } else {
461                 if (ipVersion == IPV4_VERSION &&
462                         NeutronSubnetIPAllocationPool.convert(pool.getPoolStart()) <
463                                 NeutronSubnetIPAllocationPool.convert(ans)) {
464                     ans = pool.getPoolStart();
465                 }
466                 if (ipVersion == IPV6_VERSION &&
467                         NeutronSubnetIPAllocationPool.convertV6(pool.getPoolStart()).compareTo(
468                                 NeutronSubnetIPAllocationPool.convertV6(ans)) < 0) {
469                     ans = pool.getPoolStart();
470                 }
471             }
472         }
473         return ans;
474     }
475
476     @Override
477     public String toString() {
478         return "NeutronSubnet [subnetUUID=" + subnetUUID + ", networkUUID=" + networkUUID + ", name=" + name
479                 + ", ipVersion=" + ipVersion + ", cidr=" + cidr + ", gatewayIP=" + gatewayIP + ", dnsNameservers="
480                 + dnsNameservers + ", allocationPools=" + allocationPools + ", hostRoutes=" + hostRoutes
481                 + ", enableDHCP=" + enableDHCP + ", tenantID=" + tenantID
482                 + ", ipv6AddressMode=" + ipV6AddressMode
483                 + ", ipv6RaMode=" + ipV6RaMode + "]";
484     }
485 }