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

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.