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