2 * Copyright (c) 2013, 2015 IBM Corporation and others. All rights reserved.
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
9 package org.opendaylight.ovsdb.openstack.netvirt.translator;
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;
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;
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;
32 @XmlAccessorType(XmlAccessType.NONE)
34 public class NeutronSubnet implements Serializable, INeutronObject {
35 private static final Logger LOGGER = LoggerFactory
36 .getLogger(NeutronCRUDInterfaces.class);
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;
46 // See OpenStack Network API v2.0 Reference for description of
47 // annotated attributes
49 @XmlElement (name = "id")
52 @XmlElement (name = "network_id")
55 @XmlElement (name = "name")
58 @XmlElement (defaultValue = "4", name = "ip_version")
61 @XmlElement (name = "cidr")
64 @XmlElement (name = "gateway_ip")
67 @XmlElement (name = "dns_nameservers")
68 List<String> dnsNameservers;
70 @XmlElement (name = "allocation_pools")
71 List<NeutronSubnetIPAllocationPool> allocationPools;
73 @XmlElement (name = "host_routes")
74 List<NeutronSubnet_HostRoute> hostRoutes;
76 @XmlElement (defaultValue = "true", name = "enable_dhcp")
79 @XmlElement (name = "tenant_id")
82 @XmlElement (name = "ipv6_address_mode", nillable = true)
83 String ipV6AddressMode;
85 @XmlElement (name = "ipv6_ra_mode", nillable = true)
88 /* stores the OpenStackPorts associated with an instance
89 * used to determine if that instance can be deleted.
91 * @deprecated, will be removed in Boron
94 List<NeutronPort> myPorts;
96 public NeutronSubnet() {
97 myPorts = new ArrayList<>();
100 // @deprecated - will be removed in Boron
101 public void setPorts(List<NeutronPort> arg) {
105 public String getID() { return subnetUUID; }
107 public void setID(String id) { this.subnetUUID = id; }
109 public String getSubnetUUID() {
113 public void setSubnetUUID(String subnetUUID) {
114 this.subnetUUID = subnetUUID;
117 public String getNetworkUUID() {
121 public void setNetworkUUID(String networkUUID) {
122 this.networkUUID = networkUUID;
125 public String getName() {
129 public void setName(String name) {
133 public Integer getIpVersion() {
137 public void setIpVersion(Integer ipVersion) {
138 this.ipVersion = ipVersion;
141 public String getCidr() {
145 public void setCidr(String cidr) {
149 public String getGatewayIP() {
153 public void setGatewayIP(String gatewayIP) {
154 this.gatewayIP = gatewayIP;
157 public List<String> getDnsNameservers() {
158 return dnsNameservers;
161 public void setDnsNameservers(List<String> dnsNameservers) {
162 this.dnsNameservers = dnsNameservers;
165 public List<NeutronSubnetIPAllocationPool> getAllocationPools() {
166 return allocationPools;
169 public void setAllocationPools(List<NeutronSubnetIPAllocationPool> allocationPools) {
170 this.allocationPools = allocationPools;
173 public List<NeutronSubnet_HostRoute> getHostRoutes() {
177 public void setHostRoutes(List<NeutronSubnet_HostRoute> hostRoutes) {
178 this.hostRoutes = hostRoutes;
181 public boolean isEnableDHCP() {
182 if (enableDHCP == null) {
188 public Boolean getEnableDHCP() { return enableDHCP; }
190 public void setEnableDHCP(Boolean newValue) {
191 enableDHCP = newValue;
194 public String getTenantID() {
198 public void setTenantID(String tenantID) {
199 this.tenantID = tenantID;
202 public String getIpV6AddressMode() { return ipV6AddressMode; }
204 public void setIpV6AddressMode(String ipV6AddressMode) { this.ipV6AddressMode = ipV6AddressMode; }
206 public String getIpV6RaMode() { return ipV6RaMode; }
208 public void setIpV6RaMode(String ipV6RaMode) { this.ipV6RaMode = ipV6RaMode; }
211 * This method copies selected fields from the object and returns them
212 * as a new object, suitable for marshaling.
215 * List of attributes to be extracted
216 * @return an OpenStackSubnets object with only the selected fields
220 public NeutronSubnet extractFields(List<String> fields) {
221 NeutronSubnet ans = new NeutronSubnet();
222 for (String s : fields) {
225 ans.setSubnetUUID(this.getSubnetUUID());
228 ans.setNetworkUUID(this.getNetworkUUID());
231 ans.setName(this.getName());
234 ans.setIpVersion(this.getIpVersion());
237 ans.setCidr(this.getCidr());
240 ans.setGatewayIP(this.getGatewayIP());
242 case "dns_nameservers":
243 List<String> nsList = new ArrayList<>();
244 nsList.addAll(this.getDnsNameservers());
245 ans.setDnsNameservers(nsList);
247 case "allocation_pools":
248 List<NeutronSubnetIPAllocationPool> aPools = new ArrayList<>();
249 aPools.addAll(this.getAllocationPools());
250 ans.setAllocationPools(aPools);
253 List<NeutronSubnet_HostRoute> hRoutes = new ArrayList<>();
254 hRoutes.addAll(this.getHostRoutes());
255 ans.setHostRoutes(hRoutes);
258 ans.setEnableDHCP(this.getEnableDHCP());
261 ans.setTenantID(this.getTenantID());
263 case "ipv6_address_mode":
264 ans.setIpV6AddressMode(this.getIpV6AddressMode());
267 ans.setIpV6RaMode(this.getIpV6RaMode());
274 // @deprecated - will be removed in Boron
275 public List<NeutronPort> getPortsInSubnet() {
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)) {
290 /* test to see if the cidr address used to define this subnet
291 * is a valid network address (an necessary condition when creating
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) {
299 SubnetUtils util = new SubnetUtils(cidr);
300 SubnetInfo info = util.getInfo();
301 if (!info.getNetworkAddress().equals(info.getAddress())) {
304 } catch (IllegalArgumentException e) {
305 LOGGER.warn("Failure in isValidCIDR()", e);
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) {
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();
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) {
330 } catch (UnknownHostException e) {
331 LOGGER.warn("Failure in isValidCIDR()", e);
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)
342 public boolean gatewayIP_Pool_overlap() {
343 for (NeutronSubnetIPAllocationPool pool : allocationPools) {
344 if (ipVersion == IPV4_VERSION && pool.contains(gatewayIP)) {
347 if (ipVersion == IPV6_VERSION && pool.containsV6(gatewayIP)) {
354 public boolean initDefaults() {
355 if (enableDHCP == null) {
358 if (ipVersion == null) {
359 ipVersion = IPV4_VERSION;
361 dnsNameservers = new ArrayList<>();
362 if (hostRoutes == null) {
363 hostRoutes = new ArrayList<>();
365 if (allocationPools == null) {
366 allocationPools = new ArrayList<>();
367 if (ipVersion == IPV4_VERSION) {
369 SubnetUtils util = new SubnetUtils(cidr);
370 SubnetInfo info = util.getInfo();
371 if (gatewayIP == null || ("").equals(gatewayIP)) {
372 gatewayIP = info.getLowAddress();
374 if (allocationPools.size() < 1) {
375 NeutronSubnetIPAllocationPool source =
376 new NeutronSubnetIPAllocationPool(info.getLowAddress(),
377 info.getHighAddress());
378 allocationPools = source.splitPool(gatewayIP);
380 } catch (IllegalArgumentException e) {
381 LOGGER.warn("Failure in initDefault()", e);
385 if (ipVersion == IPV6_VERSION) {
386 String[] parts = cidr.split("/");
387 if (parts.length != 2) {
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;
399 if (allocationPools.size() < 1) {
400 NeutronSubnetIPAllocationPool source =
401 new NeutronSubnetIPAllocationPool(lowAddress,
403 allocationPools = source.splitPoolV6(gatewayIP);
405 } catch (Exception e) {
406 LOGGER.warn("Failure in initDefault()", e);
414 /* this method tests to see if the supplied IPv4 address
415 * is valid for this subnet or not
417 public boolean isValidIP(String ipAddress) {
418 if (ipVersion == IPV4_VERSION) {
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);
429 if (ipVersion == IPV6_VERSION) {
430 String[] parts = cidr.split("/");
432 int length = Integer.parseInt(parts[1]);
433 byte[] cidrBytes = InetAddress.getByName(parts[0]).getAddress();
434 byte[] ipBytes = InetAddress.getByName(ipAddress).getAddress();
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))))) {
443 } catch (UnknownHostException e) {
444 LOGGER.warn("Failure in isValidIP()", e);
451 /* method to get the lowest available address of the subnet.
452 * go through all the allocation pools and keep the lowest of their
455 public String getLowAddr() {
457 for (NeutronSubnetIPAllocationPool pool : allocationPools) {
459 ans = pool.getPoolStart();
461 if (ipVersion == IPV4_VERSION &&
462 NeutronSubnetIPAllocationPool.convert(pool.getPoolStart()) <
463 NeutronSubnetIPAllocationPool.convert(ans)) {
464 ans = pool.getPoolStart();
466 if (ipVersion == IPV6_VERSION &&
467 NeutronSubnetIPAllocationPool.convertV6(pool.getPoolStart()).compareTo(
468 NeutronSubnetIPAllocationPool.convertV6(ans)) < 0) {
469 ans = pool.getPoolStart();
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 + "]";