2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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
8 package org.opendaylight.genius.mdsalutil;
10 import com.google.common.net.InetAddresses;
11 import com.google.common.primitives.Ints;
12 import com.google.common.primitives.UnsignedBytes;
13 import java.math.BigInteger;
14 import java.net.Inet4Address;
15 import java.net.InetAddress;
16 import java.net.UnknownHostException;
17 import java.util.LinkedList;
18 import java.util.List;
19 import java.util.Locale;
20 import java.util.Optional;
21 import java.util.concurrent.ExecutionException;
22 import org.apache.commons.net.util.SubnetUtils;
23 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
24 import org.opendaylight.mdsal.binding.api.DataBroker;
25 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
35 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
36 import org.opendaylight.yangtools.yang.common.Uint64;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
40 public final class NWUtil {
41 private static final Logger LOG = LoggerFactory.getLogger(NWUtil.class);
42 private static final BigInteger HIGH_128_INT = new BigInteger(new byte[] {
43 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
50 public static long convertInetAddressToLong(InetAddress address) {
51 byte[] ipAddressRaw = address.getAddress();
52 return ((ipAddressRaw[0] & 0xFF) << 3 * 8)
53 + ((ipAddressRaw[1] & 0xFF) << 2 * 8)
54 + ((ipAddressRaw[2] & 0xFF) << 1 * 8)
55 + (ipAddressRaw[3] & 0xFF)
60 * Converts IPv4 Address in long to String.
61 * {@link #longToIpv4(long, long)} fixes the issue of {@link MDSALUtil#longToIp(long, long)}
62 * not handling IP address greater than byte.
64 * @param ipAddress IP Address to be converted to String
65 * @param mask Network mask to be appended
66 * @return IP Address converted to String
68 public static String longToIpv4(final long ipAddress, final long mask) {
69 final StringBuilder builder = new StringBuilder(20);
70 final Inet4Address address = InetAddresses.fromInteger((int)ipAddress);
71 builder.append(address.toString());
73 builder.append("/").append(mask);
75 return builder.toString();
78 public static int ipAddressToInt(String ipAddr) throws UnknownHostException {
79 InetAddress subnetAddress = InetAddress.getByName(ipAddr);
80 return Ints.fromByteArray(subnetAddress.getAddress());
83 public static byte[] parseMacAddress(String macAddress) {
86 String[] addressPart = macAddress.split(NwConstants.MACADDR_SEP);
87 int size = addressPart.length;
89 byte[] part = new byte[size];
90 for (int i = 0; i < size; i++) {
91 cur = UnsignedBytes.parseUnsignedByte(addressPart[i], 16);
98 public static String toStringIpAddress(byte[] ipAddress) {
100 if (ipAddress == null) {
105 ip = InetAddress.getByAddress(ipAddress).getHostAddress();
106 } catch (UnknownHostException e) {
107 final String msg = "UnknownHostException while converting ip to string";
109 throw new RuntimeException(msg, e);
116 * Accepts a MAC address and returns the corresponding long, where the MAC
117 * bytes are set on the lower order bytes of the long.
119 * @param macAddress The MAC
120 * @return a long containing the mac address bytes
122 public static long macByteToLong(byte[] macAddress) {
124 for (int i = 0; i < 6; i++) {
125 long temp = (macAddress[i] & 0xffL) << (5 - i) * 8;
132 * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not
133 * matter, and returns the corresponding long, where the MAC bytes are set
134 * on the lower order bytes of the long.
138 * @return a long containing the mac address bytes
140 public static long macToLong(MacAddress macAddress) {
141 return macByteToLong(parseMacAddress(macAddress.getValue()));
144 public static String toStringMacAddress(byte[] macAddress) {
145 if (macAddress == null) {
149 StringBuilder sb = new StringBuilder(18);
151 for (byte macAddres : macAddress) {
152 String tmp = UnsignedBytes.toString(macAddres, 16).toUpperCase(Locale.getDefault());
153 if (tmp.length() == 1 || macAddres == (byte) 0) {
157 sb.append(NwConstants.MACADDR_SEP);
161 return sb.toString();
165 * Returns the ids of the currently operative DPNs.
166 * @param dataBroker instance of databroker
167 * @return List of DPNs
168 * @throws ExecutionException in case of a technical (!) error while reading
169 * @throws InterruptedException if the transaction is interrupted
171 public static List<Uint64> getOperativeDPNs(DataBroker dataBroker) throws ExecutionException, InterruptedException {
172 List<Uint64> result = new LinkedList<>();
173 InstanceIdentifier<Nodes> nodesInstanceIdentifier = InstanceIdentifier.builder(Nodes.class).build();
174 Optional<Nodes> nodesOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
175 LogicalDatastoreType.OPERATIONAL, nodesInstanceIdentifier);
176 if (!nodesOptional.isPresent()) {
179 for (Node node : nodesOptional.get().nonnullNode().values()) {
180 NodeId nodeId = node.getId();
181 if (nodeId != null) {
182 Uint64 dpnId = MDSALUtil.getDpnIdFromNodeName(nodeId);
190 * Utility API to check if the supplied ipAddress is IPv4 Address.
192 * @param ipAddress string-ified text of a possible IP address
193 * @return true if ipAddress is an IPv4Address and false otherwise
195 public static Boolean isIpv4Address(String ipAddress) {
197 InetAddress address = InetAddress.getByName(ipAddress);
198 return address instanceof Inet4Address;
199 } catch (UnknownHostException e) {
200 final String msg = "UnknownHostException while checking whether '" + ipAddress + "' is an IPv4 address";
201 // Double LOG & re-throw anti pattern usually bad, exceptionally OK here, just to be sure this is seen:
202 LOG.error("UnknownHostException while checking whether {} is an IPv4 address",ipAddress,e);
203 throw new RuntimeException(msg, e);
208 * Checks if a given ipAddress belongs to a specific subnet.
210 * @param ipAddress The Ip Address to check
211 * @param subnetCidr Subnet represented as string with CIDR
212 * @return true if the ipAddress belongs to the Subnet, or false if it
213 * doesn't belong or the IpAddress string cannot be converted to an
216 public static boolean isIpInSubnet(int ipAddress, String subnetCidr) {
217 String[] subSplit = subnetCidr.split("/");
218 if (subSplit.length < 2) {
222 String subnetStr = subSplit[0];
223 int prefixLength = Integer.parseInt(subSplit[1]);
225 int subnet = ipAddressToInt(subnetStr);
226 int mask = -1 << 32 - prefixLength;
228 return (subnet & mask) == (ipAddress & mask);
230 } catch (UnknownHostException ex) {
231 LOG.error("Subnet string {} not convertible to InetAdddress ", subnetStr, ex);
237 * Checks if IP address is within CIDR range.
239 * @param ipAddress the ip address
240 * @param cidr the cidr
241 * @return true, if ip address is in range
243 public static boolean isIpAddressInRange(IpAddress ipAddress, IpPrefix cidr) {
244 if (ipAddress.getIpv4Address() != null && cidr.getIpv4Prefix() != null) {
245 SubnetUtils subnetUtils = new SubnetUtils(cidr.stringValue());
246 return subnetUtils.getInfo().isInRange(ipAddress.stringValue());
247 } else if (ipAddress.getIpv6Address() != null && cidr.getIpv6Prefix() != null) {
248 return isIpAddressInRange(ipAddress.getIpv6Address(), cidr.getIpv6Prefix());
254 * Checks if IPv6 address is within CIDR range.
256 * @param ipv6Address the IPv6 address
257 * @param cidr the cidr
258 * @return true, if IPv6 address is in range
260 public static boolean isIpAddressInRange(Ipv6Address ipv6Address, Ipv6Prefix cidr) {
261 String strCidr = String.valueOf(cidr.getValue());
262 String[] arrayCidr = strCidr.split("/");
263 String networkAddress = arrayCidr[0];
264 int bits = Integer.parseInt(arrayCidr[1]);
266 // Get valid format inetaddress for both prefix and subnet CIDR
267 InetAddress cidrValidStringLiteral = InetAddresses.forString(networkAddress);
268 InetAddress ipv6AddressValidStringLiteral = InetAddresses.forString(ipv6Address.getValue());
270 // now turn that byte array into an integer
271 BigInteger range = new BigInteger(cidrValidStringLiteral.getAddress());
273 // define our mask as a bit integer by shifting our 111..11 bits to the left
274 BigInteger mask = HIGH_128_INT.shiftLeft(128 - bits);
275 BigInteger lowIp = range.and(mask);
276 BigInteger highIp = lowIp.add(mask.not());
278 BigInteger ip = new BigInteger(ipv6AddressValidStringLiteral.getAddress());
279 if (lowIp.compareTo(ip) <= 0 && highIp.compareTo(ip) >= 0) {
286 * Utility API that returns the corresponding ipPrefix based on the ipAddress.
288 * @param ipAddress string text of an IP address
289 * @return ipAddress appended with a "/32" prefix (if IPv4), else "/128" prefix (for IPv6)
291 public static String toIpPrefix(String ipAddress) {
292 return isIpv4Address(ipAddress) ? ipAddress + NwConstants.IPV4PREFIX
293 : ipAddress + NwConstants.IPV6PREFIX;
297 * Utility API that returns the corresponding etherType based on the ipPrefix address family.
298 * @param ipPrefix the ipPrefix address string either IPv4 prefix or IPv6 prefix.
299 * @return etherType of given ipPrefix.
301 public static int getEtherTypeFromIpPrefix(String ipPrefix) {
302 if (ipPrefix.contains("/")) {
303 ipPrefix = ipPrefix.substring(0, ipPrefix.indexOf("/"));
305 IpAddress ipAddress = IpAddressBuilder.getDefaultInstance(ipPrefix);
306 if (ipAddress.getIpv4Address() != null) {
307 return NwConstants.ETHTYPE_IPV4;
308 } else if (ipAddress.getIpv6Address() != null) {
309 return NwConstants.ETHTYPE_IPV6;
311 throw new IllegalArgumentException("Invalid IP Prefix: " + ipPrefix);