MRI version bump for Aluminium
[genius.git] / mdsalutil / mdsalutil-api / src / main / java / org / opendaylight / genius / mdsalutil / NWUtil.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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 package org.opendaylight.genius.mdsalutil;
9
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;
39
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
44     });
45
46     private NWUtil() {
47
48     }
49
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)
56                 & 0xffffffffL;
57     }
58
59     /**
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.
63     *
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
67     */
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());
72         if (mask != 0) {
73             builder.append("/").append(mask);
74         }
75         return builder.toString();
76     }
77
78     public static int ipAddressToInt(String ipAddr) throws UnknownHostException {
79         InetAddress subnetAddress = InetAddress.getByName(ipAddr);
80         return Ints.fromByteArray(subnetAddress.getAddress());
81     }
82
83     public static byte[] parseMacAddress(String macAddress) {
84         byte cur;
85
86         String[] addressPart = macAddress.split(NwConstants.MACADDR_SEP);
87         int size = addressPart.length;
88
89         byte[] part = new byte[size];
90         for (int i = 0; i < size; i++) {
91             cur = UnsignedBytes.parseUnsignedByte(addressPart[i], 16);
92             part[i] = cur;
93         }
94
95         return part;
96     }
97
98     public static String toStringIpAddress(byte[] ipAddress) {
99         String ip = "";
100         if (ipAddress == null) {
101             return ip;
102         }
103
104         try {
105             ip = InetAddress.getByAddress(ipAddress).getHostAddress();
106         } catch (UnknownHostException e) {
107             final String msg = "UnknownHostException while converting ip to string";
108             LOG.error(msg, e);
109             throw new RuntimeException(msg, e);
110         }
111
112         return ip;
113     }
114
115     /**
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.
118      *
119      * @param macAddress The MAC
120      * @return a long containing the mac address bytes
121      */
122     public static long macByteToLong(byte[] macAddress) {
123         long mac = 0;
124         for (int i = 0; i < 6; i++) {
125             long temp = (macAddress[i] & 0xffL) << (5 - i) * 8;
126             mac |= temp;
127         }
128         return mac;
129     }
130
131     /**
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.
135      *
136      * @param macAddress
137      *            in String format
138      * @return a long containing the mac address bytes
139      */
140     public static long macToLong(MacAddress macAddress) {
141         return macByteToLong(parseMacAddress(macAddress.getValue()));
142     }
143
144     public static String toStringMacAddress(byte[] macAddress) {
145         if (macAddress == null) {
146             return "";
147         }
148
149         StringBuilder sb = new StringBuilder(18);
150
151         for (byte macAddres : macAddress) {
152             String tmp = UnsignedBytes.toString(macAddres, 16).toUpperCase(Locale.getDefault());
153             if (tmp.length() == 1 || macAddres == (byte) 0) {
154                 sb.append("0");
155             }
156             sb.append(tmp);
157             sb.append(NwConstants.MACADDR_SEP);
158         }
159
160         sb.setLength(17);
161         return sb.toString();
162     }
163
164     /**
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
170      */
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()) {
177             return result;
178         }
179         for (Node node : nodesOptional.get().nonnullNode().values()) {
180             NodeId nodeId = node.getId();
181             if (nodeId != null) {
182                 Uint64 dpnId = MDSALUtil.getDpnIdFromNodeName(nodeId);
183                 result.add(dpnId);
184             }
185         }
186         return result;
187     }
188
189     /**
190      * Utility API to check if the supplied ipAddress is IPv4 Address.
191      *
192      * @param ipAddress string-ified text of a possible IP address
193      * @return true if ipAddress is an IPv4Address and false otherwise
194      */
195     public static Boolean isIpv4Address(String ipAddress) {
196         try {
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);
204         }
205     }
206
207     /**
208      * Checks if a given ipAddress belongs to a specific subnet.
209      *
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
214      *     InetAddress
215      */
216     public static boolean isIpInSubnet(int ipAddress, String subnetCidr) {
217         String[] subSplit = subnetCidr.split("/");
218         if (subSplit.length < 2) {
219             return false;
220         }
221
222         String subnetStr = subSplit[0];
223         int prefixLength = Integer.parseInt(subSplit[1]);
224         try {
225             int subnet = ipAddressToInt(subnetStr);
226             int mask = -1 << 32 - prefixLength;
227
228             return (subnet & mask) == (ipAddress & mask);
229
230         } catch (UnknownHostException ex) {
231             LOG.error("Subnet string {} not convertible to InetAdddress ", subnetStr, ex);
232             return false;
233         }
234     }
235
236     /**
237      * Checks if IP address is within CIDR range.
238      *
239      * @param ipAddress the ip address
240      * @param cidr the cidr
241      * @return true, if ip address is in range
242      */
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());
249         }
250         return false;
251     }
252
253     /**
254      * Checks if IPv6 address is within CIDR range.
255      *
256      * @param ipv6Address the IPv6 address
257      * @param cidr the cidr
258      * @return true, if IPv6 address is in range
259      */
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]);
265
266         // Get valid format inetaddress for both prefix and subnet CIDR
267         InetAddress cidrValidStringLiteral = InetAddresses.forString(networkAddress);
268         InetAddress ipv6AddressValidStringLiteral = InetAddresses.forString(ipv6Address.getValue());
269
270         // now turn that byte array into an integer
271         BigInteger range = new BigInteger(cidrValidStringLiteral.getAddress());
272
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());
277
278         BigInteger ip = new BigInteger(ipv6AddressValidStringLiteral.getAddress());
279         if (lowIp.compareTo(ip) <= 0 && highIp.compareTo(ip) >= 0) {
280             return true;
281         }
282         return false;
283     }
284
285     /**
286      * Utility API that returns the corresponding ipPrefix based on the ipAddress.
287      *
288      * @param ipAddress string text of an IP address
289      * @return ipAddress appended with a "/32" prefix (if IPv4), else "/128" prefix (for IPv6)
290      */
291     public static String toIpPrefix(String ipAddress) {
292         return isIpv4Address(ipAddress) ? ipAddress + NwConstants.IPV4PREFIX
293                                         : ipAddress + NwConstants.IPV6PREFIX;
294     }
295
296     /**
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.
300      */
301     public static int getEtherTypeFromIpPrefix(String ipPrefix) {
302         if (ipPrefix.contains("/")) {
303             ipPrefix = ipPrefix.substring(0, ipPrefix.indexOf("/"));
304         }
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;
310         } else {
311             throw new IllegalArgumentException("Invalid IP Prefix: " + ipPrefix);
312         }
313     }
314 }