Merge "Fixed a typo on a comment in IPv4.java."
[controller.git] / opendaylight / sal / api / src / main / java / org / opendaylight / controller / sal / utils / NetUtils.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. 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
9 package org.opendaylight.controller.sal.utils;
10
11 import java.net.Inet4Address;
12 import java.net.Inet6Address;
13 import java.net.InetAddress;
14 import java.net.UnknownHostException;
15 import java.util.regex.Matcher;
16 import java.util.regex.Pattern;
17
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 /**
22  * Utility class containing the common utility functions needed for operating on
23  * networking data structures
24  */
25 public abstract class NetUtils {
26     protected static final Logger logger = LoggerFactory.getLogger(NetUtils.class);
27     /**
28      * Constant holding the number of bits in a byte
29      */
30     public static final int NumBitsInAByte = 8;
31
32     /**
33      * Constant holding the number of bytes in MAC Address
34      */
35     public static final int MACAddrLengthInBytes = 6;
36
37     /**
38      * Constant holding the number of words in MAC Address
39      */
40     public static final int MACAddrLengthInWords = 3;
41
42     /**
43      * Constant holding the broadcast MAC address
44      */
45     private static final byte[] BroadcastMACAddr = {-1, -1, -1, -1, -1, -1};
46
47     /**
48      * Converts a 4 bytes array into an integer number
49      *
50      * @param ba
51      *            the 4 bytes long byte array
52      * @return the integer number
53      */
54     public static int byteArray4ToInt(byte[] ba) {
55         if (ba == null || ba.length != 4) {
56             return 0;
57         }
58         return (0xff & ba[0]) << 24 | (0xff & ba[1]) << 16 | (0xff & ba[2]) << 8 | (0xff & ba[3]);
59     }
60
61     /**
62      * Converts a long to 6 bytes array for mac addresses
63      * @param addr
64      * @return
65      */
66
67     public static byte[] longToByteArray6(long addr){
68         byte[] mac = new byte[6];
69         for(int i = 0; i < 6; i++){
70             mac[i] = (byte) (addr >> (i*8));
71         }
72         return mac;
73     }
74
75
76     /**
77      * Converts an integer number into a 4 bytes array
78      *
79      * @param i
80      *            the integer number
81      * @return the byte array
82      */
83     public static byte[] intToByteArray4(int i) {
84         return new byte[] { (byte) ((i >> 24) & 0xff), (byte) ((i >> 16) & 0xff), (byte) ((i >> 8) & 0xff),
85                 (byte) (i & 0xff) };
86     }
87
88     /**
89      * Converts an IP address passed as integer value into the respective
90      * InetAddress object
91      *
92      * @param address
93      *            the IP address in integer form
94      * @return the IP address in InetAddress form
95      */
96     public static InetAddress getInetAddress(int address) {
97         InetAddress ip = null;
98         try {
99             ip = InetAddress.getByAddress(NetUtils.intToByteArray4(address));
100         } catch (UnknownHostException e) {
101             logger.error("", e);
102         }
103         return ip;
104     }
105
106     /**
107      * Return the InetAddress Network Mask given the length of the prefix bit
108      * mask. The prefix bit mask indicates the contiguous leading bits that are
109      * NOT masked out. Example: A prefix bit mask length of 8 will give an
110      * InetAddress Network Mask of 255.0.0.0
111      *
112      * @param prefixMaskLength
113      *            integer representing the length of the prefix network mask
114      * @param isV6
115      *            boolean representing the IP version of the returned address
116      * @return
117      */
118     public static InetAddress getInetNetworkMask(int prefixMaskLength, boolean isV6) {
119         if (prefixMaskLength < 0 || (!isV6 && prefixMaskLength > 32) || (isV6 && prefixMaskLength > 128)) {
120             return null;
121         }
122         byte v4Address[] = { 0, 0, 0, 0 };
123         byte v6Address[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
124         byte address[] = (isV6) ? v6Address : v4Address;
125         int numBytes = prefixMaskLength / 8;
126         int numBits = prefixMaskLength % 8;
127         int i = 0;
128         for (; i < numBytes; i++) {
129             address[i] = (byte) 0xff;
130         }
131         if (numBits > 0) {
132             int rem = 0;
133             for (int j = 0; j < numBits; j++) {
134                 rem |= 1 << (7 - j);
135             }
136             address[i] = (byte) rem;
137         }
138
139         try {
140             return InetAddress.getByAddress(address);
141         } catch (UnknownHostException e) {
142             logger.error("", e);
143         }
144         return null;
145     }
146
147     /**
148      * Returns the prefix size in bits of the specified subnet mask. Example:
149      * For the subnet mask ff.ff.ff.e0 it returns 25 while for ff.00.00.00 it
150      * returns 8. If the passed subnetMask array is null, 0 is returned.
151      *
152      * @param subnetMask
153      *            the subnet mask as byte array
154      * @return the prefix length as number of bits
155      */
156     public static int getSubnetMaskLength(byte[] subnetMask) {
157         int maskLength = 0;
158         if (subnetMask != null && (subnetMask.length == 4 || subnetMask.length == 16)) {
159             int index = 0;
160             while (index < subnetMask.length && subnetMask[index] == (byte) 0xFF) {
161                 maskLength += NetUtils.NumBitsInAByte;
162                 index++;
163             }
164             if (index != subnetMask.length) {
165                 int bits = NetUtils.NumBitsInAByte - 1;
166                 while (bits >= 0 && (subnetMask[index] & 1 << bits)  != 0) {
167                     bits--;
168                     maskLength++;
169                 }
170             }
171         }
172         return maskLength;
173     }
174
175     /**
176      * Returns the prefix size in bits of the specified subnet mask. Example:
177      * For the subnet mask 255.255.255.128 it returns 25 while for 255.0.0.0 it
178      * returns 8. If the passed subnetMask object is null, 0 is returned
179      *
180      * @param subnetMask
181      *            the subnet mask as InetAddress
182      * @return the prefix length as number of bits
183      */
184     public static int getSubnetMaskLength(InetAddress subnetMask) {
185         return subnetMask == null ? 0 : NetUtils.getSubnetMaskLength(subnetMask.getAddress());
186     }
187
188     /**
189      * Given an IP address and a prefix network mask length, it returns the
190      * equivalent subnet prefix IP address Example: for ip = "172.28.30.254" and
191      * maskLen = 25 it will return "172.28.30.128"
192      *
193      * @param ip
194      *            the IP address in InetAddress form
195      * @param maskLen
196      *            the length of the prefix network mask
197      * @return the subnet prefix IP address in InetAddress form
198      */
199     public static InetAddress getSubnetPrefix(InetAddress ip, int maskLen) {
200         int bytes = maskLen / 8;
201         int bits = maskLen % 8;
202         byte modifiedByte;
203         byte[] sn = ip.getAddress();
204         if (bits > 0) {
205             modifiedByte = (byte) (sn[bytes] >> (8 - bits));
206             sn[bytes] = (byte) (modifiedByte << (8 - bits));
207             bytes++;
208         }
209         for (; bytes < sn.length; bytes++) {
210             sn[bytes] = (byte) (0);
211         }
212         try {
213             return InetAddress.getByAddress(sn);
214         } catch (UnknownHostException e) {
215             return null;
216         }
217     }
218
219     /**
220      * Checks if the test address and mask conflicts with the filter address and
221      * mask
222      *
223      * For example: testAddress: 172.28.2.23 testMask: 255.255.255.0
224      * filtAddress: 172.28.1.10 testMask: 255.255.255.0 conflict
225      *
226      * testAddress: 172.28.2.23 testMask: 255.255.255.0 filtAddress: 172.28.1.10
227      * testMask: 255.255.0.0 do not conflict
228      *
229      * Null parameters are permitted
230      *
231      * @param testAddress
232      * @param filterAddress
233      * @param testMask
234      * @param filterMask
235      * @return
236      */
237     public static boolean inetAddressConflict(InetAddress testAddress, InetAddress filterAddress, InetAddress testMask,
238             InetAddress filterMask) {
239         // Sanity check
240         if ((testAddress == null) || (filterAddress == null)) {
241             return false;
242         }
243
244         // Presence check
245         if (isAny(testAddress) || isAny(filterAddress)) {
246             return false;
247         }
248
249         int testMaskLen = (testMask == null) ? ((testAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
250                 .getSubnetMaskLength(testMask);
251         int filterMaskLen = NetUtils.getSubnetMaskLength(filterMask);
252
253         // Mask length check. Test mask has to be more specific than filter one
254         if (testMaskLen < filterMaskLen) {
255             return true;
256         }
257
258         // Subnet Prefix on filter mask length must be the same
259         InetAddress prefix1 = getSubnetPrefix(testAddress, filterMaskLen);
260         InetAddress prefix2 = getSubnetPrefix(filterAddress, filterMaskLen);
261         return (!prefix1.equals(prefix2));
262     }
263
264     /**
265      * Returns true if the passed MAC address is all zero
266      *
267      * @param mac
268      *            the byte array representing the MAC address
269      * @return true if all MAC bytes are zero
270      */
271     public static boolean isZeroMAC(byte[] mac) {
272         for (short i = 0; i < 6; i++) {
273             if (mac[i] != 0) {
274                 return false;
275             }
276         }
277         return true;
278     }
279
280     /**
281      * Returns true if the MAC address is the broadcast MAC address and false
282      * otherwise.
283      *
284      * @param MACAddress
285      * @return
286      */
287     public static boolean isBroadcastMACAddr(byte[] MACAddress) {
288         if (MACAddress.length == MACAddrLengthInBytes) {
289             for (int i = 0; i < 6; i++) {
290                 if (MACAddress[i] != BroadcastMACAddr[i]) {
291                     return false;
292                 }
293             }
294             return true;
295         }
296
297         return false;
298     }
299
300     /**
301      * Returns true if the MAC address is a multicast MAC address and false
302      * otherwise. Note that this explicitly returns false for the broadcast MAC
303      * address.
304      *
305      * @param MACAddress
306      * @return
307      */
308     public static boolean isMulticastMACAddr(byte[] MACAddress) {
309         if (MACAddress.length == MACAddrLengthInBytes && !isBroadcastMACAddr(MACAddress)) {
310             if (MACAddress[0] % 2 == 1) {
311                 return true;
312             }
313         }
314         return false;
315     }
316
317     /**
318      * Returns true if the passed InetAddress contains all zero
319      *
320      * @param ip
321      *            the IP address to test
322      * @return true if the address is all zero
323      */
324     public static boolean isAny(InetAddress ip) {
325         for (byte b : ip.getAddress()) {
326             if (b != 0) {
327                 return false;
328             }
329         }
330         return true;
331     }
332
333     public static boolean fieldsConflict(int field1, int field2) {
334         if ((field1 == 0) || (field2 == 0) || (field1 == field2)) {
335             return false;
336         }
337         return true;
338     }
339
340     public static InetAddress parseInetAddress(String addressString) {
341         InetAddress address = null;
342         try {
343             address = InetAddress.getByName(addressString);
344         } catch (UnknownHostException e) {
345             logger.error("", e);
346         }
347         return address;
348     }
349
350     /**
351      * Checks if the passed IP v4 address in string form is valid The address
352      * may specify a mask at the end as "/MM"
353      *
354      * @param cidr
355      *            the v4 address as A.B.C.D/MM
356      * @return
357      */
358     public static boolean isIPv4AddressValid(String cidr) {
359         if (cidr == null) {
360             return false;
361         }
362
363         String values[] = cidr.split("/");
364         Pattern ipv4Pattern = Pattern
365                 .compile("(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])");
366         Matcher mm = ipv4Pattern.matcher(values[0]);
367         if (!mm.matches()) {
368             return false;
369         }
370         if (values.length >= 2) {
371             int prefix = Integer.valueOf(values[1]);
372             if ((prefix < 0) || (prefix > 32)) {
373                 return false;
374             }
375         }
376         return true;
377     }
378
379     /**
380      * Checks if the passed IP v6 address in string form is valid The address
381      * may specify a mask at the end as "/MMM"
382      *
383      * @param cidr
384      *            the v6 address as A::1/MMM
385      * @return
386      */
387     public static boolean isIPv6AddressValid(String cidr) {
388         if (cidr == null) {
389             return false;
390         }
391
392         String values[] = cidr.split("/");
393         try {
394             // when given an IP address, InetAddress.getByName validates the ip
395             // address
396             InetAddress addr = InetAddress.getByName(values[0]);
397             if (!(addr instanceof Inet6Address)) {
398                 return false;
399             }
400         } catch (UnknownHostException ex) {
401             return false;
402         }
403
404         if (values.length >= 2) {
405             int prefix = Integer.valueOf(values[1]);
406             if ((prefix < 0) || (prefix > 128)) {
407                 return false;
408             }
409         }
410         return true;
411     }
412
413     /**
414      * Checks if the passed IP address in string form is a valid v4 or v6
415      * address. The address may specify a mask at the end as "/MMM"
416      *
417      * @param cidr
418      *            the v4 or v6 address as IP/MMM
419      * @return
420      */
421     public static boolean isIPAddressValid(String cidr) {
422         return NetUtils.isIPv4AddressValid(cidr) || NetUtils.isIPv6AddressValid(cidr);
423     }
424
425     /*
426      * Following utilities are useful when you need to compare or bit shift java
427      * primitive type variable which are inerently signed
428      */
429     /**
430      * Returns the unsigned value of the passed byte variable
431      *
432      * @param b
433      *            the byte value
434      * @return the int variable containing the unsigned byte value
435      */
436     public static int getUnsignedByte(byte b) {
437         return (b > 0) ? (int) b : (b & 0x7F | 0x80);
438     }
439
440     /**
441      * Return the unsigned value of the passed short variable
442      *
443      * @param s
444      *            the short value
445      * @return the int variable containing the unsigned short value
446      */
447     public static int getUnsignedShort(short s) {
448         return (s > 0) ? (int) s : (s & 0x7FFF | 0x8000);
449     }
450
451     /**
452      * Returns the highest v4 or v6 InetAddress
453      *
454      * @param v6
455      *            true for IPv6, false for Ipv4
456      * @return The highest IPv4 or IPv6 address
457      */
458     public static InetAddress gethighestIP(boolean v6) {
459         try {
460             return (v6) ? InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") : InetAddress
461                     .getByName("255.255.255.255");
462         } catch (UnknownHostException e) {
463             return null;
464         }
465     }
466 }