Merge "BUG-5602: OFP-Li implements a YANG notification which notifies its application...
[openflowplugin.git] / applications / statistics-manager / src / main / java / org / opendaylight / openflowplugin / applications / statistics / manager / impl / helper / MatchComparatorHelper.java
1 /**
2  * Copyright (c) 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 package org.opendaylight.openflowplugin.applications.statistics.manager.impl.helper;
9
10 import java.math.BigInteger;
11 import java.net.Inet4Address;
12 import java.net.InetAddress;
13 import java.net.UnknownHostException;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.MacAddressFilter;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpSourceHardwareAddress;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpTargetHardwareAddress;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpTargetHardwareAddressBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatch;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchArbitraryBitMask;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6Match;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 import com.google.common.annotations.VisibleForTesting;
36 import com.google.common.net.InetAddresses;
37 import com.google.common.primitives.UnsignedBytes;
38
39 /**
40  * @author joe
41  * @author sai.marapareddy@gmail.com
42  *
43  */
44 public class MatchComparatorHelper {
45
46     private static final Logger LOG = LoggerFactory.getLogger(MatchComparatorHelper.class);
47     private static final int DEFAULT_SUBNET = 32;
48     private static final int IPV4_MASK_LENGTH = 32;
49     private static final int SHIFT_OCTET_1 = 24;
50     private static final int SHIFT_OCTET_2 = 16;
51     private static final int SHIFT_OCTET_3 = 8;
52     private static final int SHIFT_OCTET_4 = 0;
53     private static final int POSITION_OCTET_1 = 0;
54     private static final int POSITION_OCTET_2 = 1;
55     private static final int POSITION_OCTET_3 = 2;
56     private static final int POSITION_OCTET_4 = 3;
57     private static final String DEFAULT_ARBITRARY_BIT_MASK = "255.255.255.255";
58     private static final String PREFIX_SEPARATOR = "/";
59     private static final int IPV4_ADDRESS_LENGTH = 32;
60     private static final int BYTE_SIZE = 8;
61
62     /*
63      * Custom EthernetMatch is required because mac address string provided by user in EthernetMatch can be in any case
64      * (upper or lower or mix). Ethernet Match which controller receives from switch is always an upper case string.
65      * Default EthernetMatch equals doesn't use equalsIgnoreCase() and hence it fails. E.g User provided mac address
66      * string in flow match is aa:bb:cc:dd:ee:ff and when controller fetch statistic data, openflow driver library
67      * returns AA:BB:CC:DD:EE:FF and default eqauls fails here.
68      */
69     @VisibleForTesting
70     static boolean ethernetMatchEquals(final EthernetMatch statsEthernetMatch, final EthernetMatch storedEthernetMatch) {
71         boolean verdict = true;
72         final Boolean checkNullValues = checkNullValues(statsEthernetMatch, storedEthernetMatch);
73         if (checkNullValues != null) {
74             verdict = checkNullValues;
75         } else {
76             verdict = ethernetMatchFieldsEquals(statsEthernetMatch.getEthernetSource(),
77                     storedEthernetMatch.getEthernetSource());
78             if (verdict) {
79                 verdict = ethernetMatchFieldsEquals(statsEthernetMatch.getEthernetDestination(),
80                         storedEthernetMatch.getEthernetDestination());
81             }
82             if (verdict) {
83                 if (statsEthernetMatch.getEthernetType() == null) {
84                     if (storedEthernetMatch.getEthernetType() != null) {
85                         verdict = false;
86                     }
87                 } else {
88                     verdict = statsEthernetMatch.getEthernetType().equals(storedEthernetMatch.getEthernetType());
89                 }
90             }
91         }
92         return verdict;
93     }
94
95     static boolean ethernetMatchFieldsEquals(final MacAddressFilter statsEthernetMatchFields,
96             final MacAddressFilter storedEthernetMatchFields) {
97         boolean verdict = true;
98         final Boolean checkNullValues = checkNullValues(statsEthernetMatchFields, storedEthernetMatchFields);
99         if (checkNullValues != null) {
100             verdict = checkNullValues;
101         } else {
102             verdict = macAddressEquals(statsEthernetMatchFields.getAddress(), storedEthernetMatchFields.getAddress());
103             if (verdict) {
104                 verdict = macAddressEquals(statsEthernetMatchFields.getMask(), storedEthernetMatchFields.getMask());
105             }
106         }
107         return verdict;
108     }
109
110     static boolean macAddressEquals(final MacAddress statsMacAddress, final MacAddress storedMacAddress) {
111         boolean verdict = true;
112         final Boolean checkNullValues = checkNullValues(statsMacAddress, storedMacAddress);
113         if (checkNullValues != null) {
114             verdict = checkNullValues;
115         } else {
116             verdict = statsMacAddress.getValue().equalsIgnoreCase(storedMacAddress.getValue());
117         }
118         return verdict;
119     }
120
121     @VisibleForTesting
122     static boolean layer3MatchEquals(final Layer3Match statsLayer3Match, final Layer3Match storedLayer3Match) {
123         boolean verdict = true;
124         if (statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4Match) {
125             final Ipv4Match statsIpv4Match = (Ipv4Match) statsLayer3Match;
126             final Ipv4Match storedIpv4Match = (Ipv4Match) storedLayer3Match;
127             verdict = MatchComparatorHelper.compareIpv4PrefixNullSafe(storedIpv4Match.getIpv4Destination(),
128                     statsIpv4Match.getIpv4Destination());
129             if (verdict) {
130                 verdict = MatchComparatorHelper.compareIpv4PrefixNullSafe(statsIpv4Match.getIpv4Source(),
131                         storedIpv4Match.getIpv4Source());
132             }
133         } else if (statsLayer3Match instanceof Ipv6Match && storedLayer3Match instanceof Ipv6Match) {
134             final Ipv6Match statsIpv6Match = (Ipv6Match) statsLayer3Match;
135             final Ipv6Match storedIpv6Match = (Ipv6Match) storedLayer3Match;
136             verdict = MatchComparatorHelper.compareIpv6PrefixNullSafe(storedIpv6Match.getIpv6Destination(),
137                     statsIpv6Match.getIpv6Destination());
138             if (verdict) {
139                 verdict = MatchComparatorHelper.compareIpv6PrefixNullSafe(statsIpv6Match.getIpv6Source(),
140                         storedIpv6Match.getIpv6Source());
141             }
142         } else if (statsLayer3Match instanceof  Ipv4MatchArbitraryBitMask && storedLayer3Match instanceof Ipv4MatchArbitraryBitMask) {
143             // At this moment storedIpv4MatchArbitraryBitMask & statsIpv4MatchArbitraryBitMask will always have non null arbitrary masks.
144             // In case of no / null arbitrary mask, statsLayer3Match will be an instance of Ipv4Match.
145             // Eg:- stats -> 1.0.1.0/255.0.255.0  stored -> 1.1.1.0/255.0.255.0
146             final Ipv4MatchArbitraryBitMask statsIpv4MatchArbitraryBitMask= (Ipv4MatchArbitraryBitMask) statsLayer3Match;
147             final Ipv4MatchArbitraryBitMask storedIpv4MatchArbitraryBitMask = (Ipv4MatchArbitraryBitMask) storedLayer3Match;
148             if ((storedIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask() != null |
149                     storedIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask() != null)) {
150                 if (storedIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask() != null) {
151                         String storedDstIpAddress = normalizeIpv4Address(storedIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask(),
152                                 storedIpv4MatchArbitraryBitMask.getIpv4DestinationArbitraryBitmask());
153                         String statsDstIpAddress = normalizeIpv4Address(statsIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask(),
154                                 statsIpv4MatchArbitraryBitMask.getIpv4DestinationArbitraryBitmask());
155                         if (MatchComparatorHelper.compareStringNullSafe(storedIpv4MatchArbitraryBitMask.getIpv4DestinationArbitraryBitmask().getValue(),
156                                 statsIpv4MatchArbitraryBitMask.getIpv4DestinationArbitraryBitmask().getValue())) {
157                             verdict = MatchComparatorHelper.compareStringNullSafe(storedDstIpAddress,
158                                     statsDstIpAddress);
159                         } else {
160                             verdict = false;
161                             return verdict;
162                         }
163                 }
164                 if (storedIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask() != null) {
165                         String storedSrcIpAddress = normalizeIpv4Address(storedIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask()
166                                 ,storedIpv4MatchArbitraryBitMask.getIpv4SourceArbitraryBitmask());
167                         String statsSrcIpAddress = normalizeIpv4Address(statsIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask()
168                                 ,statsIpv4MatchArbitraryBitMask.getIpv4SourceArbitraryBitmask());
169                         if (MatchComparatorHelper.compareStringNullSafe(storedIpv4MatchArbitraryBitMask.getIpv4SourceArbitraryBitmask().getValue(),
170                                 statsIpv4MatchArbitraryBitMask.getIpv4SourceArbitraryBitmask().getValue())) {
171                             verdict = MatchComparatorHelper.compareStringNullSafe(storedSrcIpAddress,
172                                     statsSrcIpAddress);
173                         } else {
174                             verdict = false;
175                         }
176                 }
177             } else {
178                 final Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match);
179                 if (nullCheckOut != null) {
180                     verdict = nullCheckOut;
181                 } else {
182                     verdict = storedLayer3Match.equals(statsLayer3Match);
183                 }
184             }
185         } else if (statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4MatchArbitraryBitMask) {
186             // Here stored netmask is an instance of Ipv4MatchArbitraryBitMask, when it is pushed in to switch
187             // it automatically converts it in to cidr format in case of certain subnet masks ( consecutive ones or zeroes)
188             // Eg:- stats src/dest -> 1.1.1.0/24  stored src/dest -> 1.1.1.0/255.255.255.0
189             final Ipv4Match statsIpv4Match = (Ipv4Match) statsLayer3Match;
190             final Ipv4MatchArbitraryBitMask storedIpv4MatchArbitraryBitMask = (Ipv4MatchArbitraryBitMask) storedLayer3Match;
191             if (storedIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask() != null) {
192                 Ipv4Prefix ipv4PrefixDestination;
193                 if (storedIpv4MatchArbitraryBitMask.getIpv4DestinationArbitraryBitmask() != null) {
194                     byte[] destByteMask = convertArbitraryMaskToByteArray(storedIpv4MatchArbitraryBitMask.getIpv4DestinationArbitraryBitmask());
195                     ipv4PrefixDestination = createPrefix(storedIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask(), destByteMask);
196                 } else {
197                     ipv4PrefixDestination = createPrefix(storedIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask());
198                 }
199                 verdict = MatchComparatorHelper.compareIpv4PrefixNullSafe(ipv4PrefixDestination, statsIpv4Match.getIpv4Destination());
200                 if (verdict == false) {
201                     return verdict;
202                 }
203             }
204             if (storedIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask() != null) {
205                 Ipv4Prefix ipv4PrefixSource;
206                 if (storedIpv4MatchArbitraryBitMask.getIpv4SourceArbitraryBitmask() != null) {
207                     byte[] srcByteMask = convertArbitraryMaskToByteArray(storedIpv4MatchArbitraryBitMask.getIpv4SourceArbitraryBitmask());
208                     ipv4PrefixSource = createPrefix(storedIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask(), srcByteMask);
209                 } else {
210                     ipv4PrefixSource = createPrefix(storedIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask());
211                 }
212                 verdict = MatchComparatorHelper.compareIpv4PrefixNullSafe(ipv4PrefixSource, statsIpv4Match.getIpv4Source());
213             }
214         } else if (statsLayer3Match instanceof ArpMatch && storedLayer3Match instanceof ArpMatch) {
215             verdict = arpMatchEquals((ArpMatch)statsLayer3Match, (ArpMatch)storedLayer3Match);
216         } else {
217             final Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match);
218             if (nullCheckOut != null) {
219                 verdict = nullCheckOut;
220             } else {
221                 verdict = storedLayer3Match.equals(statsLayer3Match);
222             }
223         }
224         return verdict;
225     }
226
227     static boolean arpMatchEquals(final ArpMatch statsArpMatch, final ArpMatch storedArpMatch) {
228
229         Integer statsOp = statsArpMatch.getArpOp();
230         Integer storedOp = storedArpMatch.getArpOp();
231
232         Boolean nullCheck = checkNullValues(statsOp, storedOp);
233         if (nullCheck != null) {
234             if (nullCheck == false) {
235                 return false;
236             }
237         } else if (!statsOp.equals(storedOp)) {
238             return false;
239         }
240
241         Ipv4Prefix statsIp = statsArpMatch.getArpSourceTransportAddress();
242         Ipv4Prefix storedIp = storedArpMatch.getArpSourceTransportAddress();
243         if (!compareIpv4PrefixNullSafe(statsIp, storedIp)) {
244             return false;
245         }
246
247         statsIp = statsArpMatch.getArpTargetTransportAddress();
248         storedIp = storedArpMatch.getArpTargetTransportAddress();
249         if (!compareIpv4PrefixNullSafe(statsIp, storedIp)) {
250             return false;
251         }
252
253         MacAddressFilter statsMac = statsArpMatch.getArpSourceHardwareAddress();
254         MacAddressFilter storedMac = storedArpMatch.getArpSourceHardwareAddress();
255         if (!ethernetMatchFieldsEquals(statsMac, storedMac)) {
256             return false;
257         }
258
259         statsMac = statsArpMatch.getArpTargetHardwareAddress();
260         storedMac = storedArpMatch.getArpTargetHardwareAddress();
261         if (!ethernetMatchFieldsEquals(statsMac, storedMac)) {
262             return false;
263         }
264
265         return true;
266     }
267
268
269     /**
270      * TODO: why don't we use the default Ipv4Prefix.equals()?
271      *
272      * @param statsIpAddress
273      * @param storedIpAddress
274      * @return true if IPv4prefixes equals
275      */
276     static boolean IpAddressEquals(final Ipv4Prefix statsIpAddress, final Ipv4Prefix storedIpAddress) {
277         final IntegerIpAddress statsIpAddressInt = MatchComparatorHelper.strIpToIntIp(statsIpAddress.getValue());
278         final IntegerIpAddress storedIpAddressInt = MatchComparatorHelper.strIpToIntIp(storedIpAddress.getValue());
279
280         if (ipAndMaskBasedMatch(statsIpAddressInt, storedIpAddressInt)) {
281             return true;
282         }
283         if (ipBasedMatch(statsIpAddressInt, storedIpAddressInt)) {
284             return true;
285         }
286         return false;
287     }
288
289     static boolean ipAndMaskBasedMatch(final IntegerIpAddress statsIpAddressInt,
290             final IntegerIpAddress storedIpAddressInt) {
291         return ((statsIpAddressInt.getIp() & statsIpAddressInt.getMask()) == (storedIpAddressInt.getIp() & storedIpAddressInt
292                 .getMask()));
293     }
294
295     static boolean ipBasedMatch(final IntegerIpAddress statsIpAddressInt, final IntegerIpAddress storedIpAddressInt) {
296         return (statsIpAddressInt.getIp() == storedIpAddressInt.getIp());
297     }
298
299
300     private static boolean IpAddressEquals(Ipv6Prefix statsIpv6, Ipv6Prefix storedIpv6) {
301         final String[] statsIpMask = statsIpv6.getValue().split("/");
302         final String[] storedIpMask = storedIpv6.getValue().split("/");
303         if (! (statsIpMask.length > 1 && storedIpMask.length > 1 &&  statsIpMask[1].equals(storedIpMask[1]))){
304             return false;
305         }
306
307         final int prefix = Integer.parseInt(statsIpMask[1]);
308         final int byteIndex = prefix/BYTE_SIZE;
309         final int lastByteBits = BYTE_SIZE - (prefix % BYTE_SIZE);
310         final InetAddress statsIp = InetAddresses.forString(statsIpMask[0]);
311         final InetAddress storedIp = InetAddresses.forString(storedIpMask[0]);
312         byte[] statsIpArr = Arrays.copyOfRange(statsIp.getAddress(),0,byteIndex+1);
313         byte[] storedIpArr = Arrays.copyOfRange(storedIp.getAddress(),0,byteIndex+1);
314         statsIpArr[byteIndex] = (byte) (statsIpArr[byteIndex] & (0XFF << lastByteBits));
315         storedIpArr[byteIndex] = (byte) (storedIpArr[byteIndex] & (0XFF << lastByteBits));
316         if(Arrays.equals(statsIpArr,storedIpArr)) {
317             return true;
318         }
319         return false;
320     }
321
322     static Boolean checkNullValues(final Object v1, final Object v2) {
323         Boolean verdict = null;
324         if (v1 == null && v2 != null) {
325             verdict = Boolean.FALSE;
326         } else if (v1 != null && v2 == null) {
327             verdict = Boolean.FALSE;
328         } else if (v1 == null && v2 == null) {
329             verdict = Boolean.TRUE;
330         }
331         return verdict;
332     }
333
334     static boolean compareIpv4PrefixNullSafe(final Ipv4Prefix statsIpv4, final Ipv4Prefix storedIpv4) {
335         boolean verdict = true;
336         final Boolean checkDestNullValuesOut = checkNullValues(storedIpv4, statsIpv4);
337         if (checkDestNullValuesOut != null) {
338             verdict = checkDestNullValuesOut;
339         } else if (!IpAddressEquals(statsIpv4, storedIpv4)) {
340             verdict = false;
341         }
342         return verdict;
343     }
344
345     static boolean compareStringNullSafe(final String stringA, final String stringB) {
346         boolean verdict = true;
347         final Boolean checkDestNullValuesOut = checkNullValues(stringA,stringB);
348         if (checkDestNullValuesOut != null) {
349             verdict = checkDestNullValuesOut;
350         } else if (!stringA.equals(stringB)) {
351             verdict = false;
352         }
353         return verdict;
354     }
355
356     private static boolean compareIpv6PrefixNullSafe(Ipv6Prefix statsIpv6, Ipv6Prefix storedIpv6) {
357         boolean verdict = true;
358         final Boolean checkDestNullValuesOut = checkNullValues(statsIpv6, storedIpv6);
359         if (checkDestNullValuesOut != null) {
360             verdict = checkDestNullValuesOut;
361         } else if (!IpAddressEquals(statsIpv6, storedIpv6)) {
362             verdict = false;
363         }
364         return verdict;
365     }
366
367     /**
368      * Method return integer version of ip address. Converted int will be mask if mask specified
369      */
370     static IntegerIpAddress strIpToIntIp(final String ipAddresss) {
371
372         final String[] parts = ipAddresss.split("/");
373         final String ip = parts[0];
374         int prefix;
375
376         if (parts.length < 2) {
377             prefix = DEFAULT_SUBNET;
378         } else {
379             prefix = Integer.parseInt(parts[1]);
380             if (prefix < 0 || prefix > IPV4_MASK_LENGTH) {
381                 final StringBuilder stringBuilder = new StringBuilder(
382                         "Valid values for mask are from range 0 - 32. Value ");
383                 stringBuilder.append(prefix);
384                 stringBuilder.append(" is invalid.");
385                 throw new IllegalStateException(stringBuilder.toString());
386             }
387         }
388
389         IntegerIpAddress integerIpAddress = null;
390
391         final Inet4Address addr = ((Inet4Address) InetAddresses.forString(ip));
392         final byte[] addrBytes = addr.getAddress();
393         // FIXME: what is meaning of anding with 0xFF? Probably could be removed.
394         final int ipInt = ((addrBytes[POSITION_OCTET_1] & 0xFF) << SHIFT_OCTET_1)
395                 | ((addrBytes[POSITION_OCTET_2] & 0xFF) << SHIFT_OCTET_2)
396                 | ((addrBytes[POSITION_OCTET_3] & 0xFF) << SHIFT_OCTET_3)
397                 | ((addrBytes[POSITION_OCTET_4] & 0xFF) << SHIFT_OCTET_4);
398
399         // FIXME: Is this valid?
400         final int mask = 0xffffffff << DEFAULT_SUBNET - prefix;
401
402         integerIpAddress = new IntegerIpAddress(ipInt, mask);
403
404         return integerIpAddress;
405     }
406
407     static boolean isArbitraryBitMask(byte[] byteMask) {
408         if (byteMask == null) {
409             return false;
410         } else {
411             ArrayList<Integer> integerMaskArrayList = new ArrayList<Integer>();
412             String maskInBits;
413             // converting byte array to bits
414             maskInBits = new BigInteger(1, byteMask).toString(2);
415             ArrayList<String> stringMaskArrayList = new ArrayList<String>(Arrays.asList(maskInBits.split("(?!^)")));
416             for(String string:stringMaskArrayList){
417                 integerMaskArrayList.add(Integer.parseInt(string));
418             }
419             return checkArbitraryBitMask(integerMaskArrayList);
420         }
421     }
422
423     static boolean checkArbitraryBitMask(ArrayList<Integer> arrayList) {
424         if (arrayList.size()>0 && arrayList.size()< IPV4_MASK_LENGTH ) {
425             // checks 0*1* case - Leading zeros in arrayList are truncated
426             return true;
427         } else {
428             //checks 1*0*1 case
429             for(int i=0; i<arrayList.size()-1;i++) {
430                 if(arrayList.get(i) ==0 && arrayList.get(i+1) == 1) {
431                     return true;
432                 }
433             }
434         }
435         return false;
436     }
437
438     static final byte[] convertArbitraryMaskToByteArray(DottedQuad mask) {
439         String maskValue;
440         if(mask.getValue() != null && mask != null){
441             maskValue  = mask.getValue();
442         } else maskValue = DEFAULT_ARBITRARY_BIT_MASK;
443         InetAddress maskInIpFormat = null;
444         try {
445             maskInIpFormat = InetAddress.getByName(maskValue);
446         } catch (UnknownHostException e) {
447             LOG.error("Failed to recognize the host while converting mask ", e);
448         }
449         byte[] bytes = maskInIpFormat.getAddress();
450         return bytes;
451     }
452
453
454     static String normalizeIpv4Address(Ipv4Address ipAddress, DottedQuad netMask) {
455         String actualIpAddress="";
456         String[] netMaskParts = netMask.getValue().split("\\.");
457         String[] ipAddressParts = ipAddress.getValue().split("\\.");
458
459         for (int i=0; i<ipAddressParts.length;i++) {
460             int integerFormatIpAddress=Integer.parseInt(ipAddressParts[i]);
461             int integerFormatNetMask=Integer.parseInt(netMaskParts[i]);
462             int ipAddressPart=(integerFormatIpAddress) & (integerFormatNetMask);
463             actualIpAddress += ipAddressPart;
464             if (i != ipAddressParts.length -1 ) {
465                 actualIpAddress = actualIpAddress+".";
466             }
467         }
468         return actualIpAddress;
469     }
470
471     static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final byte [] bytemask){
472         return createPrefix(ipv4Address, String.valueOf(countBits(bytemask)));
473     }
474
475     static int countBits(final byte[] mask) {
476         int netmask = 0;
477         for (byte b : mask) {
478             netmask += Integer.bitCount(UnsignedBytes.toInt(b));
479         }
480         return netmask;
481     }
482
483     static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address){
484         return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + IPV4_ADDRESS_LENGTH);
485     }
486
487     static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final String mask){
488         /*
489          * Ipv4Address has already validated the address part of the prefix,
490          * It is mandated to comply to the same regexp as the address
491          * There is absolutely no point rerunning additional checks vs this
492          * Note - there is no canonical form check here!!!
493          */
494         if (null != mask && !mask.isEmpty()) {
495             return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + mask);
496         } else {
497             return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + IPV4_ADDRESS_LENGTH);
498         }
499     }
500 }