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