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<NeutronPort>();
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 Iterator<String> i = fields.iterator();
223 while (i.hasNext()) {
225 if (s.equals("id")) {
226 ans.setSubnetUUID(this.getSubnetUUID());
228 if (s.equals("network_id")) {
229 ans.setNetworkUUID(this.getNetworkUUID());
231 if (s.equals("name")) {
232 ans.setName(this.getName());
234 if (s.equals("ip_version")) {
235 ans.setIpVersion(this.getIpVersion());
237 if (s.equals("cidr")) {
238 ans.setCidr(this.getCidr());
240 if (s.equals("gateway_ip")) {
241 ans.setGatewayIP(this.getGatewayIP());
243 if (s.equals("dns_nameservers")) {
244 List<String> nsList = new ArrayList<String>();
245 nsList.addAll(this.getDnsNameservers());
246 ans.setDnsNameservers(nsList);
248 if (s.equals("allocation_pools")) {
249 List<NeutronSubnetIPAllocationPool> aPools = new ArrayList<NeutronSubnetIPAllocationPool>();
250 aPools.addAll(this.getAllocationPools());
251 ans.setAllocationPools(aPools);
253 if (s.equals("host_routes")) {
254 List<NeutronSubnet_HostRoute> hRoutes = new ArrayList<NeutronSubnet_HostRoute>();
255 hRoutes.addAll(this.getHostRoutes());
256 ans.setHostRoutes(hRoutes);
258 if (s.equals("enable_dhcp")) {
259 ans.setEnableDHCP(this.getEnableDHCP());
261 if (s.equals("tenant_id")) {
262 ans.setTenantID(this.getTenantID());
264 if (s.equals("ipv6_address_mode")) {
265 ans.setIpV6AddressMode(this.getIpV6AddressMode());
267 if (s.equals("ipv6_ra_mode")) {
268 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<NeutronPort>();
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 = ((Inet6Address) 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 Iterator<NeutronSubnetIPAllocationPool> i = allocationPools.iterator();
344 while (i.hasNext()) {
345 NeutronSubnetIPAllocationPool pool = i.next();
346 if (ipVersion == IPV4_VERSION && pool.contains(gatewayIP)) {
349 if (ipVersion == IPV6_VERSION && pool.containsV6(gatewayIP)) {
356 public boolean initDefaults() {
357 if (enableDHCP == null) {
360 if (ipVersion == null) {
361 ipVersion = IPV4_VERSION;
363 dnsNameservers = new ArrayList<String>();
364 if (hostRoutes == null) {
365 hostRoutes = new ArrayList<NeutronSubnet_HostRoute>();
367 if (allocationPools == null) {
368 allocationPools = new ArrayList<NeutronSubnetIPAllocationPool>();
369 if (ipVersion == IPV4_VERSION) {
371 SubnetUtils util = new SubnetUtils(cidr);
372 SubnetInfo info = util.getInfo();
373 if (gatewayIP == null || ("").equals(gatewayIP)) {
374 gatewayIP = info.getLowAddress();
376 if (allocationPools.size() < 1) {
377 NeutronSubnetIPAllocationPool source =
378 new NeutronSubnetIPAllocationPool(info.getLowAddress(),
379 info.getHighAddress());
380 allocationPools = source.splitPool(gatewayIP);
382 } catch (IllegalArgumentException e) {
383 LOGGER.warn("Failure in initDefault()", e);
387 if (ipVersion == IPV6_VERSION) {
388 String[] parts = cidr.split("/");
389 if (parts.length != 2) {
393 int length = Integer.parseInt(parts[1]);
394 BigInteger lowAddress_bi = NeutronSubnetIPAllocationPool.convertV6(parts[0]);
395 String lowAddress = NeutronSubnetIPAllocationPool.bigIntegerToIP(lowAddress_bi.add(BigInteger.ONE));
396 BigInteger mask = BigInteger.ONE.shiftLeft(length).subtract(BigInteger.ONE);
397 String highAddress = NeutronSubnetIPAllocationPool.bigIntegerToIP(lowAddress_bi.add(mask).subtract(BigInteger.ONE));
398 if (gatewayIP == null || ("").equals(gatewayIP)) {
399 gatewayIP = lowAddress;
401 if (allocationPools.size() < 1) {
402 NeutronSubnetIPAllocationPool source =
403 new NeutronSubnetIPAllocationPool(lowAddress,
405 allocationPools = source.splitPoolV6(gatewayIP);
407 } catch (Exception e) {
408 LOGGER.warn("Failure in initDefault()", e);
416 /* this method tests to see if the supplied IPv4 address
417 * is valid for this subnet or not
419 public boolean isValidIP(String ipAddress) {
420 if (ipVersion == IPV4_VERSION) {
422 SubnetUtils util = new SubnetUtils(cidr);
423 SubnetInfo info = util.getInfo();
424 return info.isInRange(ipAddress);
425 } catch (IllegalArgumentException e) {
426 LOGGER.warn("Failure in isValidIP()", e);
431 if (ipVersion == IPV6_VERSION) {
432 String[] parts = cidr.split("/");
434 int length = Integer.parseInt(parts[1]);
435 byte[] cidrBytes = ((Inet6Address) InetAddress.getByName(parts[0])).getAddress();
436 byte[] ipBytes = ((Inet6Address) InetAddress.getByName(ipAddress)).getAddress();
438 for (i = 0; i < length; i++) {
439 if (((((int) cidrBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES)))) !=
440 ((((int) ipBytes[i/IPV6_LENGTH_BYTES]) & IPV6_LSB_MASK) & (1 << (IPV6_BYTE_OFFSET-(i%IPV6_LENGTH_BYTES))))) {
445 } catch (UnknownHostException e) {
446 LOGGER.warn("Failure in isValidIP()", e);
453 /* method to get the lowest available address of the subnet.
454 * go through all the allocation pools and keep the lowest of their
457 public String getLowAddr() {
459 Iterator<NeutronSubnetIPAllocationPool> i = allocationPools.iterator();
460 while (i.hasNext()) {
461 NeutronSubnetIPAllocationPool pool = i.next();
463 ans = pool.getPoolStart();
466 if (ipVersion == IPV4_VERSION &&
467 NeutronSubnetIPAllocationPool.convert(pool.getPoolStart()) <
468 NeutronSubnetIPAllocationPool.convert(ans)) {
469 ans = pool.getPoolStart();
471 if (ipVersion == IPV6_VERSION &&
472 NeutronSubnetIPAllocationPool.convertV6(pool.getPoolStart()).compareTo(NeutronSubnetIPAllocationPool.convertV6(ans)) < 0) {
473 ans = pool.getPoolStart();
481 public String toString() {
482 return "NeutronSubnet [subnetUUID=" + subnetUUID + ", networkUUID=" + networkUUID + ", name=" + name
483 + ", ipVersion=" + ipVersion + ", cidr=" + cidr + ", gatewayIP=" + gatewayIP + ", dnsNameservers="
484 + dnsNameservers + ", allocationPools=" + allocationPools + ", hostRoutes=" + hostRoutes
485 + ", enableDHCP=" + enableDHCP + ", tenantID=" + tenantID
486 + ", ipv6AddressMode=" + ipV6AddressMode
487 + ", ipv6RaMode=" + ipV6RaMode + "]";