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