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.netvirt.openstack.netvirt.translator;
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;
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;
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;
30 @XmlAccessorType(XmlAccessType.NONE)
32 public class NeutronSubnet implements Serializable, INeutronObject {
33 private static final Logger LOGGER = LoggerFactory
34 .getLogger(NeutronCRUDInterfaces.class);
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;
44 // See OpenStack Network API v2.0 Reference for description of
45 // annotated attributes
47 @XmlElement (name = "id")
50 @XmlElement (name = "network_id")
53 @XmlElement (name = "name")
56 @XmlElement (defaultValue = "4", name = "ip_version")
59 @XmlElement (name = "cidr")
62 @XmlElement (name = "gateway_ip")
65 @XmlElement (name = "dns_nameservers")
66 List<String> dnsNameservers;
68 @XmlElement (name = "allocation_pools")
69 List<NeutronSubnetIPAllocationPool> allocationPools;
71 @XmlElement (name = "host_routes")
72 List<NeutronSubnet_HostRoute> hostRoutes;
74 @XmlElement (defaultValue = "true", name = "enable_dhcp")
77 @XmlElement (name = "tenant_id")
80 @XmlElement (name = "ipv6_address_mode", nillable = true)
81 String ipV6AddressMode;
83 @XmlElement (name = "ipv6_ra_mode", nillable = true)
86 /* stores the OpenStackPorts associated with an instance
87 * used to determine if that instance can be deleted.
89 * @deprecated, will be removed in Boron
92 List<NeutronPort> myPorts;
94 public NeutronSubnet() {
95 myPorts = new ArrayList<>();
98 // @deprecated - will be removed in Boron
99 public void setPorts(List<NeutronPort> arg) {
103 public String getID() { return subnetUUID; }
105 public void setID(String id) { this.subnetUUID = id; }
107 public String getSubnetUUID() {
111 public void setSubnetUUID(String subnetUUID) {
112 this.subnetUUID = subnetUUID;
115 public String getNetworkUUID() {
119 public void setNetworkUUID(String networkUUID) {
120 this.networkUUID = networkUUID;
123 public String getName() {
127 public void setName(String name) {
131 public Integer getIpVersion() {
135 public void setIpVersion(Integer ipVersion) {
136 this.ipVersion = ipVersion;
139 public String getCidr() {
143 public void setCidr(String cidr) {
147 public String getGatewayIP() {
151 public void setGatewayIP(String gatewayIP) {
152 this.gatewayIP = gatewayIP;
155 public List<String> getDnsNameservers() {
156 return dnsNameservers;
159 public void setDnsNameservers(List<String> dnsNameservers) {
160 this.dnsNameservers = dnsNameservers;
163 public List<NeutronSubnetIPAllocationPool> getAllocationPools() {
164 return allocationPools;
167 public void setAllocationPools(List<NeutronSubnetIPAllocationPool> allocationPools) {
168 this.allocationPools = allocationPools;
171 public List<NeutronSubnet_HostRoute> getHostRoutes() {
175 public void setHostRoutes(List<NeutronSubnet_HostRoute> hostRoutes) {
176 this.hostRoutes = hostRoutes;
179 public boolean isEnableDHCP() {
180 if (enableDHCP == null) {
186 public Boolean getEnableDHCP() { return enableDHCP; }
188 public void setEnableDHCP(Boolean newValue) {
189 enableDHCP = newValue;
192 public String getTenantID() {
196 public void setTenantID(String tenantID) {
197 this.tenantID = tenantID;
200 public String getIpV6AddressMode() { return ipV6AddressMode; }
202 public void setIpV6AddressMode(String ipV6AddressMode) { this.ipV6AddressMode = ipV6AddressMode; }
204 public String getIpV6RaMode() { return ipV6RaMode; }
206 public void setIpV6RaMode(String ipV6RaMode) { this.ipV6RaMode = ipV6RaMode; }
209 * This method copies selected fields from the object and returns them
210 * as a new object, suitable for marshaling.
213 * List of attributes to be extracted
214 * @return an OpenStackSubnets object with only the selected fields
218 public NeutronSubnet extractFields(List<String> fields) {
219 NeutronSubnet ans = new NeutronSubnet();
220 for (String s : fields) {
223 ans.setSubnetUUID(this.getSubnetUUID());
226 ans.setNetworkUUID(this.getNetworkUUID());
229 ans.setName(this.getName());
232 ans.setIpVersion(this.getIpVersion());
235 ans.setCidr(this.getCidr());
238 ans.setGatewayIP(this.getGatewayIP());
240 case "dns_nameservers":
241 List<String> nsList = new ArrayList<>();
242 nsList.addAll(this.getDnsNameservers());
243 ans.setDnsNameservers(nsList);
245 case "allocation_pools":
246 List<NeutronSubnetIPAllocationPool> aPools = new ArrayList<>();
247 aPools.addAll(this.getAllocationPools());
248 ans.setAllocationPools(aPools);
251 List<NeutronSubnet_HostRoute> hRoutes = new ArrayList<>();
252 hRoutes.addAll(this.getHostRoutes());
253 ans.setHostRoutes(hRoutes);
256 ans.setEnableDHCP(this.getEnableDHCP());
259 ans.setTenantID(this.getTenantID());
261 case "ipv6_address_mode":
262 ans.setIpV6AddressMode(this.getIpV6AddressMode());
265 ans.setIpV6RaMode(this.getIpV6RaMode());
272 // @deprecated - will be removed in Boron
273 public List<NeutronPort> getPortsInSubnet() {
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)) {
288 /* test to see if the cidr address used to define this subnet
289 * is a valid network address (an necessary condition when creating
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) {
297 SubnetUtils util = new SubnetUtils(cidr);
298 SubnetInfo info = util.getInfo();
299 if (!info.getNetworkAddress().equals(info.getAddress())) {
302 } catch (IllegalArgumentException e) {
303 LOGGER.warn("Failure in isValidCIDR()", e);
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) {
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();
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) {
328 } catch (UnknownHostException e) {
329 LOGGER.warn("Failure in isValidCIDR()", e);
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)
340 public boolean gatewayIP_Pool_overlap() {
341 for (NeutronSubnetIPAllocationPool pool : allocationPools) {
342 if (ipVersion == IPV4_VERSION && pool.contains(gatewayIP)) {
345 if (ipVersion == IPV6_VERSION && pool.containsV6(gatewayIP)) {
352 public boolean initDefaults() {
353 if (enableDHCP == null) {
356 if (ipVersion == null) {
357 ipVersion = IPV4_VERSION;
359 dnsNameservers = new ArrayList<>();
360 if (hostRoutes == null) {
361 hostRoutes = new ArrayList<>();
363 if (allocationPools == null) {
364 allocationPools = new ArrayList<>();
365 if (ipVersion == IPV4_VERSION) {
367 SubnetUtils util = new SubnetUtils(cidr);
368 SubnetInfo info = util.getInfo();
369 if (gatewayIP == null || ("").equals(gatewayIP)) {
370 gatewayIP = info.getLowAddress();
372 if (allocationPools.size() < 1) {
373 NeutronSubnetIPAllocationPool source =
374 new NeutronSubnetIPAllocationPool(info.getLowAddress(),
375 info.getHighAddress());
376 allocationPools = source.splitPool(gatewayIP);
378 } catch (IllegalArgumentException e) {
379 LOGGER.warn("Failure in initDefault()", e);
383 if (ipVersion == IPV6_VERSION) {
384 String[] parts = cidr.split("/");
385 if (parts.length != 2) {
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;
397 if (allocationPools.size() < 1) {
398 NeutronSubnetIPAllocationPool source =
399 new NeutronSubnetIPAllocationPool(lowAddress,
401 allocationPools = source.splitPoolV6(gatewayIP);
403 } catch (Exception e) {
404 LOGGER.warn("Failure in initDefault()", e);
412 /* this method tests to see if the supplied IPv4 address
413 * is valid for this subnet or not
415 public boolean isValidIP(String ipAddress) {
416 if (ipVersion == IPV4_VERSION) {
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);
427 if (ipVersion == IPV6_VERSION) {
428 String[] parts = cidr.split("/");
430 int length = Integer.parseInt(parts[1]);
431 byte[] cidrBytes = InetAddress.getByName(parts[0]).getAddress();
432 byte[] ipBytes = InetAddress.getByName(ipAddress).getAddress();
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))))) {
441 } catch (UnknownHostException e) {
442 LOGGER.warn("Failure in isValidIP()", e);
449 /* method to get the lowest available address of the subnet.
450 * go through all the allocation pools and keep the lowest of their
453 public String getLowAddr() {
455 for (NeutronSubnetIPAllocationPool pool : allocationPools) {
457 ans = pool.getPoolStart();
459 if (ipVersion == IPV4_VERSION &&
460 NeutronSubnetIPAllocationPool.convert(pool.getPoolStart()) <
461 NeutronSubnetIPAllocationPool.convert(ans)) {
462 ans = pool.getPoolStart();
464 if (ipVersion == IPV6_VERSION &&
465 NeutronSubnetIPAllocationPool.convertV6(pool.getPoolStart()).compareTo(
466 NeutronSubnetIPAllocationPool.convertV6(ans)) < 0) {
467 ans = pool.getPoolStart();
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 + "]";