Bug 6110: Fixed bugs in statistics manager due to race condition.
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / util / 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.impl.util;
9
10 import com.google.common.annotations.VisibleForTesting;
11 import com.google.common.net.InetAddresses;
12 import com.google.common.primitives.UnsignedBytes;
13 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
14 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
15 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
16 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.MacAddressFilter;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatch;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchArbitraryBitMask;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6Match;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchArbitraryBitMask;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.opendaylight.ipv6.arbitrary.bitmask.fields.rev160224.Ipv6ArbitraryMask;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 import java.math.BigInteger;
32 import java.net.Inet4Address;
33 import java.net.InetAddress;
34 import java.net.UnknownHostException;
35 import java.util.ArrayList;
36 import java.util.Arrays;
37
38 /**
39  * @author joe
40  * @author sai.marapareddy@gmail.com
41  *
42  */
43 public class MatchComparatorHelper {
44
45     private static final Logger LOG = LoggerFactory.getLogger(MatchComparatorHelper.class);
46     private static final int DEFAULT_SUBNET = 32;
47     private static final int IPV4_MASK_LENGTH = 32;
48     private static final int SHIFT_OCTET_1 = 24;
49     private static final int SHIFT_OCTET_2 = 16;
50     private static final int SHIFT_OCTET_3 = 8;
51     private static final int SHIFT_OCTET_4 = 0;
52     private static final int POSITION_OCTET_1 = 0;
53     private static final int POSITION_OCTET_2 = 1;
54     private static final int POSITION_OCTET_3 = 2;
55     private static final int POSITION_OCTET_4 = 3;
56     private static final String DEFAULT_ARBITRARY_BIT_MASK = "255.255.255.255";
57     private static final String DEFAULT_IPV6_ARBITRARY_BIT_MASK = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
58     private static final String PREFIX_SEPARATOR = "/";
59     private static final int IPV4_ADDRESS_LENGTH = 32;
60     private static final int IPV6_ADDRESS_LENGTH = 128;
61     private static final int BYTE_SIZE = 8;
62
63     /*
64      * Custom EthernetMatch is required because mac address string provided by user in EthernetMatch can be in any case
65      * (upper or lower or mix). Ethernet Match which controller receives from switch is always an upper case string.
66      * Default EthernetMatch equals doesn't use equalsIgnoreCase() and hence it fails. E.g User provided mac address
67      * string in flow match is aa:bb:cc:dd:ee:ff and when controller fetch statistic data, openflow driver library
68      * returns AA:BB:CC:DD:EE:FF and default eqauls fails here.
69      */
70     @VisibleForTesting
71     static boolean ethernetMatchEquals(final EthernetMatch statsEthernetMatch, final EthernetMatch storedEthernetMatch) {
72         boolean verdict = true;
73         final Boolean checkNullValues = checkNullValues(statsEthernetMatch, storedEthernetMatch);
74         if (checkNullValues != null) {
75             verdict = checkNullValues;
76         } else {
77             verdict = ethernetMatchFieldsEquals(statsEthernetMatch.getEthernetSource(),
78                     storedEthernetMatch.getEthernetSource());
79             if (verdict) {
80                 verdict = ethernetMatchFieldsEquals(statsEthernetMatch.getEthernetDestination(),
81                         storedEthernetMatch.getEthernetDestination());
82             }
83             if (verdict) {
84                 if (statsEthernetMatch.getEthernetType() == null) {
85                     if (storedEthernetMatch.getEthernetType() != null) {
86                         verdict = false;
87                     }
88                 } else {
89                     verdict = statsEthernetMatch.getEthernetType().equals(storedEthernetMatch.getEthernetType());
90                 }
91             }
92         }
93         return verdict;
94     }
95
96     static boolean ethernetMatchFieldsEquals(final MacAddressFilter statsEthernetMatchFields,
97                                              final MacAddressFilter storedEthernetMatchFields) {
98         boolean verdict = true;
99         final Boolean checkNullValues = checkNullValues(statsEthernetMatchFields, storedEthernetMatchFields);
100         if (checkNullValues != null) {
101             verdict = checkNullValues;
102         } else {
103             verdict = macAddressEquals(statsEthernetMatchFields.getAddress(), storedEthernetMatchFields.getAddress());
104             if (verdict) {
105                 verdict = macAddressEquals(statsEthernetMatchFields.getMask(), storedEthernetMatchFields.getMask());
106             }
107         }
108         return verdict;
109     }
110
111     static boolean macAddressEquals(final MacAddress statsMacAddress, final MacAddress storedMacAddress) {
112         boolean verdict = true;
113         final Boolean checkNullValues = checkNullValues(statsMacAddress, storedMacAddress);
114         if (checkNullValues != null) {
115             verdict = checkNullValues;
116         } else {
117             verdict = statsMacAddress.getValue().equalsIgnoreCase(storedMacAddress.getValue());
118         }
119         return verdict;
120     }
121
122     @VisibleForTesting
123     static boolean layer3MatchEquals(final Layer3Match statsLayer3Match, final Layer3Match storedLayer3Match) {
124         boolean verdict = true;
125         if (statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4Match) {
126             final Ipv4Match statsIpv4Match = (Ipv4Match) statsLayer3Match;
127             final Ipv4Match storedIpv4Match = (Ipv4Match) storedLayer3Match;
128             verdict = MatchComparatorHelper.compareIpv4PrefixNullSafe(storedIpv4Match.getIpv4Destination(),
129                     statsIpv4Match.getIpv4Destination());
130             if (verdict) {
131                 verdict = MatchComparatorHelper.compareIpv4PrefixNullSafe(statsIpv4Match.getIpv4Source(),
132                         storedIpv4Match.getIpv4Source());
133             }
134         } else if (statsLayer3Match instanceof Ipv6Match && storedLayer3Match instanceof Ipv6Match) {
135             final Ipv6Match statsIpv6Match = (Ipv6Match) statsLayer3Match;
136             final Ipv6Match storedIpv6Match = (Ipv6Match) storedLayer3Match;
137             verdict = MatchComparatorHelper.compareIpv6PrefixNullSafe(storedIpv6Match.getIpv6Destination(),
138                     statsIpv6Match.getIpv6Destination());
139             if (verdict) {
140                 verdict = MatchComparatorHelper.compareIpv6PrefixNullSafe(statsIpv6Match.getIpv6Source(),
141                         storedIpv6Match.getIpv6Source());
142             }
143         } else if (statsLayer3Match instanceof  Ipv4MatchArbitraryBitMask && storedLayer3Match instanceof Ipv4MatchArbitraryBitMask) {
144             // At this moment storedIpv4MatchArbitraryBitMask & statsIpv4MatchArbitraryBitMask will always have non null arbitrary masks.
145             // In case of no / null arbitrary mask, statsLayer3Match will be an instance of Ipv4Match.
146             // Eg:- stats -> 1.0.1.0/255.0.255.0  stored -> 1.1.1.0/255.0.255.0
147             final Ipv4MatchArbitraryBitMask statsIpv4MatchArbitraryBitMask= (Ipv4MatchArbitraryBitMask) statsLayer3Match;
148             final Ipv4MatchArbitraryBitMask storedIpv4MatchArbitraryBitMask = (Ipv4MatchArbitraryBitMask) storedLayer3Match;
149             if ((storedIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask() != null |
150                     storedIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask() != null)) {
151                 if (storedIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask() != null) {
152                     String storedDstIpAddress = normalizeIpv4Address(storedIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask(),
153                             storedIpv4MatchArbitraryBitMask.getIpv4DestinationArbitraryBitmask());
154                     String statsDstIpAddress = normalizeIpv4Address(statsIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask(),
155                             statsIpv4MatchArbitraryBitMask.getIpv4DestinationArbitraryBitmask());
156                     if (MatchComparatorHelper.compareStringNullSafe(storedIpv4MatchArbitraryBitMask.getIpv4DestinationArbitraryBitmask().getValue(),
157                             statsIpv4MatchArbitraryBitMask.getIpv4DestinationArbitraryBitmask().getValue())) {
158                         verdict = MatchComparatorHelper.compareStringNullSafe(storedDstIpAddress,
159                                 statsDstIpAddress);
160                     } else {
161                         verdict = false;
162                         return verdict;
163                     }
164                 }
165                 if (storedIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask() != null) {
166                     String storedSrcIpAddress = normalizeIpv4Address(storedIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask()
167                             ,storedIpv4MatchArbitraryBitMask.getIpv4SourceArbitraryBitmask());
168                     String statsSrcIpAddress = normalizeIpv4Address(statsIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask()
169                             ,statsIpv4MatchArbitraryBitMask.getIpv4SourceArbitraryBitmask());
170                     if (MatchComparatorHelper.compareStringNullSafe(storedIpv4MatchArbitraryBitMask.getIpv4SourceArbitraryBitmask().getValue(),
171                             statsIpv4MatchArbitraryBitMask.getIpv4SourceArbitraryBitmask().getValue())) {
172                         verdict = MatchComparatorHelper.compareStringNullSafe(storedSrcIpAddress,
173                                 statsSrcIpAddress);
174                     } else {
175                         verdict = false;
176                     }
177                 }
178             } else {
179                 final Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match);
180                 if (nullCheckOut != null) {
181                     verdict = nullCheckOut;
182                 } else {
183                     verdict = storedLayer3Match.equals(statsLayer3Match);
184                 }
185             }
186         } else if (statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4MatchArbitraryBitMask) {
187             // Here stored netmask is an instance of Ipv4MatchArbitraryBitMask, when it is pushed in to switch
188             // it automatically converts it in to cidr format in case of certain subnet masks ( consecutive ones or zeroes)
189             // Eg:- stats src/dest -> 1.1.1.0/24  stored src/dest -> 1.1.1.0/255.255.255.0
190             final Ipv4Match statsIpv4Match = (Ipv4Match) statsLayer3Match;
191             final Ipv4MatchArbitraryBitMask storedIpv4MatchArbitraryBitMask = (Ipv4MatchArbitraryBitMask) storedLayer3Match;
192             if (storedIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask() != null) {
193                 Ipv4Prefix ipv4PrefixDestination;
194                 if (storedIpv4MatchArbitraryBitMask.getIpv4DestinationArbitraryBitmask() != null) {
195                     byte[] destByteMask = convertArbitraryMaskToByteArray(storedIpv4MatchArbitraryBitMask.getIpv4DestinationArbitraryBitmask());
196                     ipv4PrefixDestination = createPrefix(storedIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask(), destByteMask);
197                 } else {
198                     ipv4PrefixDestination = createPrefix(storedIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask());
199                 }
200                 verdict = MatchComparatorHelper.compareIpv4PrefixNullSafe(ipv4PrefixDestination, statsIpv4Match.getIpv4Destination());
201                 if (verdict == false) {
202                     return verdict;
203                 }
204             }
205             if (storedIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask() != null) {
206                 Ipv4Prefix ipv4PrefixSource;
207                 if (storedIpv4MatchArbitraryBitMask.getIpv4SourceArbitraryBitmask() != null) {
208                     byte[] srcByteMask = convertArbitraryMaskToByteArray(storedIpv4MatchArbitraryBitMask.getIpv4SourceArbitraryBitmask());
209                     ipv4PrefixSource = createPrefix(storedIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask(), srcByteMask);
210                 } else {
211                     ipv4PrefixSource = createPrefix(storedIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask());
212                 }
213                 verdict = MatchComparatorHelper.compareIpv4PrefixNullSafe(ipv4PrefixSource, statsIpv4Match.getIpv4Source());
214             }
215         } else if (statsLayer3Match instanceof Ipv4MatchArbitraryBitMask && storedLayer3Match instanceof Ipv4Match) {
216             // Here stored netmask is an instance of Ipv4MatchArbitraryBitMask, when it is pushed in to switch
217             // it automatically converts it in to cidr format in case of certain subnet masks ( consecutive ones or zeroes)
218             // Eg:- stats src/dest -> 1.1.1.0/24  stored src/dest -> 1.1.1.0/255.255.255.0
219             final Ipv4Match storedIpv4Match = (Ipv4Match) storedLayer3Match;
220             final Ipv4MatchArbitraryBitMask statsIpv4MatchArbitraryBitMask = (Ipv4MatchArbitraryBitMask) statsLayer3Match;
221             if (statsIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask() != null) {
222                 Ipv4Prefix ipv4PrefixDestination;
223                 if (statsIpv4MatchArbitraryBitMask.getIpv4DestinationArbitraryBitmask() != null) {
224                     byte[] destByteMask = convertArbitraryMaskToByteArray(statsIpv4MatchArbitraryBitMask.getIpv4DestinationArbitraryBitmask());
225                     ipv4PrefixDestination = createPrefix(statsIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask(), destByteMask);
226                 } else {
227                     ipv4PrefixDestination = createPrefix(statsIpv4MatchArbitraryBitMask.getIpv4DestinationAddressNoMask());
228                 }
229                 verdict = MatchComparatorHelper.compareIpv4PrefixNullSafe(ipv4PrefixDestination, storedIpv4Match.getIpv4Destination());
230                 if (verdict == false) {
231                     return verdict;
232                 }
233             }
234             if (statsIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask() != null) {
235                 Ipv4Prefix ipv4PrefixSource;
236                 if (statsIpv4MatchArbitraryBitMask.getIpv4SourceArbitraryBitmask() != null) {
237                     byte[] srcByteMask = convertArbitraryMaskToByteArray(statsIpv4MatchArbitraryBitMask.getIpv4SourceArbitraryBitmask());
238                     ipv4PrefixSource = createPrefix(statsIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask(), srcByteMask);
239                 } else {
240                     ipv4PrefixSource = createPrefix(statsIpv4MatchArbitraryBitMask.getIpv4SourceAddressNoMask());
241                 }
242                 verdict = MatchComparatorHelper.compareIpv4PrefixNullSafe(ipv4PrefixSource, storedIpv4Match.getIpv4Source());
243             }
244         } else if (statsLayer3Match instanceof Ipv6MatchArbitraryBitMask && storedLayer3Match instanceof Ipv6MatchArbitraryBitMask) {
245             // At this moment storedIpv6MatchArbitraryBitMask & statsIpv6MatchArbitraryBitMask will always have non null arbitrary masks.
246             // In case of no / null arbitrary mask, statsLayer3Match will be an instance of Ipv6Match.
247             // Eg:- stats src/dest  -> 2001:2001:2001:2001:2001:2001:2001:2001/FFFF:FFFF:FFFF:FFFF:0000:FFFF:FFFF:FFF0
248             //     stored src/dest  -> 2001:2001:2001:2001:2001:2001:2001:2001/FFFF:FFFF:FFFF:FFFF:0000:FFFF:FFFF:FFF0
249             final Ipv6MatchArbitraryBitMask statsIpv6MatchArbitraryBitMask= (Ipv6MatchArbitraryBitMask) statsLayer3Match;
250             final Ipv6MatchArbitraryBitMask storedIpv6MatchArbitraryBitMask = (Ipv6MatchArbitraryBitMask) storedLayer3Match;
251             if ((storedIpv6MatchArbitraryBitMask.getIpv6DestinationAddressNoMask() != null |
252                     storedIpv6MatchArbitraryBitMask.getIpv6SourceAddressNoMask() != null)) {
253                 if (storedIpv6MatchArbitraryBitMask.getIpv6DestinationAddressNoMask() != null) {
254                     String storedDstIpAddress = normalizeIpv6Address(storedIpv6MatchArbitraryBitMask.getIpv6DestinationAddressNoMask(),
255                             storedIpv6MatchArbitraryBitMask.getIpv6DestinationArbitraryBitmask());
256                     String statsDstIpAddress = normalizeIpv6Address(statsIpv6MatchArbitraryBitMask.getIpv6DestinationAddressNoMask(),
257                             statsIpv6MatchArbitraryBitMask.getIpv6DestinationArbitraryBitmask());
258                     String storedDstMask = extractIpv6CanonicalForm(storedIpv6MatchArbitraryBitMask.
259                             getIpv6DestinationArbitraryBitmask().getValue()).getHostAddress();
260                     String statsDstMask = extractIpv6CanonicalForm(statsIpv6MatchArbitraryBitMask.
261                             getIpv6DestinationArbitraryBitmask().getValue()).getHostAddress();
262                     if (MatchComparatorHelper.compareStringNullSafe(storedDstMask,statsDstMask)) {
263                         verdict = MatchComparatorHelper.compareStringNullSafe(storedDstIpAddress,
264                                 statsDstIpAddress);
265                     } else {
266                         verdict = false;
267                         return verdict;
268                     }
269                 }
270                 if (storedIpv6MatchArbitraryBitMask.getIpv6SourceAddressNoMask() != null) {
271                     String storedSrcIpAddress = normalizeIpv6Address(storedIpv6MatchArbitraryBitMask.getIpv6SourceAddressNoMask()
272                             ,storedIpv6MatchArbitraryBitMask.getIpv6SourceArbitraryBitmask());
273                     String statsSrcIpAddress = normalizeIpv6Address(statsIpv6MatchArbitraryBitMask.getIpv6SourceAddressNoMask()
274                             ,statsIpv6MatchArbitraryBitMask.getIpv6SourceArbitraryBitmask());
275                     String storedSrcMask = extractIpv6CanonicalForm(storedIpv6MatchArbitraryBitMask.
276                             getIpv6SourceArbitraryBitmask().getValue()).getHostAddress();
277                     String statsSrcMask = extractIpv6CanonicalForm(statsIpv6MatchArbitraryBitMask.
278                             getIpv6SourceArbitraryBitmask().getValue()).getHostAddress();
279                     if (MatchComparatorHelper.compareStringNullSafe(storedSrcMask, statsSrcMask)) {
280                         verdict = MatchComparatorHelper.compareStringNullSafe(storedSrcIpAddress,
281                                 statsSrcIpAddress);
282                     } else {
283                         verdict = false;
284                     }
285                 }
286             } else {
287                 final Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match);
288                 if (nullCheckOut != null) {
289                     verdict = nullCheckOut;
290                 } else {
291                     verdict = storedLayer3Match.equals(statsLayer3Match);
292                 }
293             }
294         } else if (statsLayer3Match instanceof Ipv6Match && storedLayer3Match instanceof Ipv6MatchArbitraryBitMask) {
295             // Here stored netmask is an instance of Ipv6MatchArbitraryBitMask, when it is pushed in to switch
296             // it automatically converts it in to cidr format in case of certain subnet masks ( consecutive ones or zeroes)
297             // Eg:- stats src/dest -> 2001:2001:2001:2001:2001:2001:2001:2001/124
298             // stored src/dest -> 2001:2001:2001:2001:2001:2001:2001:2001/FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFF0
299             final Ipv6Match statsIpv6Match = (Ipv6Match) statsLayer3Match;
300             final Ipv6MatchArbitraryBitMask storedIpv6MatchArbitraryBitMask = (Ipv6MatchArbitraryBitMask) storedLayer3Match;
301             if (storedIpv6MatchArbitraryBitMask.getIpv6DestinationAddressNoMask() != null) {
302                 Ipv6Prefix ipv6PrefixDestination;
303                 if (storedIpv6MatchArbitraryBitMask.getIpv6DestinationArbitraryBitmask() != null) {
304                     byte[] destByteMask = convertIpv6ArbitraryMaskToByteArray(storedIpv6MatchArbitraryBitMask.getIpv6DestinationArbitraryBitmask());
305                     ipv6PrefixDestination = createPrefix(storedIpv6MatchArbitraryBitMask.getIpv6DestinationAddressNoMask(), destByteMask);
306                 } else {
307                     ipv6PrefixDestination = createPrefix(storedIpv6MatchArbitraryBitMask.getIpv6DestinationAddressNoMask());
308                 }
309                 verdict = MatchComparatorHelper.compareIpv6PrefixNullSafe(ipv6PrefixDestination, statsIpv6Match.getIpv6Destination());
310                 if (verdict == false) {
311                     return verdict;
312                 }
313             }
314             if (storedIpv6MatchArbitraryBitMask.getIpv6SourceAddressNoMask() != null) {
315                 Ipv6Prefix ipv6PrefixSource;
316                 if (storedIpv6MatchArbitraryBitMask.getIpv6SourceArbitraryBitmask() != null) {
317                     byte[] srcByteMask = convertIpv6ArbitraryMaskToByteArray(storedIpv6MatchArbitraryBitMask.getIpv6SourceArbitraryBitmask());
318                     ipv6PrefixSource = createPrefix(storedIpv6MatchArbitraryBitMask.getIpv6SourceAddressNoMask(), srcByteMask);
319                 } else {
320                     ipv6PrefixSource = createPrefix(storedIpv6MatchArbitraryBitMask.getIpv6SourceAddressNoMask());
321                 }
322                 verdict = MatchComparatorHelper.compareIpv6PrefixNullSafe(ipv6PrefixSource, statsIpv6Match.getIpv6Source());
323             }
324         } else if (statsLayer3Match instanceof Ipv6MatchArbitraryBitMask && storedLayer3Match instanceof Ipv6Match) {
325             // Here stored netmask is an instance of Ipv6MatchArbitraryBitMask, when it is pushed in to switch
326             // it automatically converts it in to cidr format in case of certain subnet masks ( consecutive ones or zeroes)
327             // Eg:- stats src/dest -> 2001:2001:2001:2001:2001:2001:2001:2001/124
328             // stored src/dest -> 2001:2001:2001:2001:2001:2001:2001:2001/FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFF0
329             final Ipv6Match storedIpv6Match = (Ipv6Match) storedLayer3Match;
330             final Ipv6MatchArbitraryBitMask statsIpv6MatchArbitraryBitMask = (Ipv6MatchArbitraryBitMask) statsLayer3Match;
331             if (statsIpv6MatchArbitraryBitMask.getIpv6DestinationAddressNoMask() != null) {
332                 Ipv6Prefix ipv6PrefixDestination;
333                 if (statsIpv6MatchArbitraryBitMask.getIpv6DestinationArbitraryBitmask() != null) {
334                     byte[] destByteMask = convertIpv6ArbitraryMaskToByteArray(statsIpv6MatchArbitraryBitMask.getIpv6DestinationArbitraryBitmask());
335                     ipv6PrefixDestination = createPrefix(statsIpv6MatchArbitraryBitMask.getIpv6DestinationAddressNoMask(), destByteMask);
336                 } else {
337                     ipv6PrefixDestination = createPrefix(statsIpv6MatchArbitraryBitMask.getIpv6DestinationAddressNoMask());
338                 }
339                 verdict = MatchComparatorHelper.compareIpv6PrefixNullSafe(ipv6PrefixDestination, storedIpv6Match.getIpv6Destination());
340                 if (verdict == false) {
341                     return verdict;
342                 }
343             }
344             if (statsIpv6MatchArbitraryBitMask.getIpv6SourceAddressNoMask() != null) {
345                 Ipv6Prefix ipv6PrefixSource;
346                 if (statsIpv6MatchArbitraryBitMask.getIpv6SourceArbitraryBitmask() != null) {
347                     byte[] srcByteMask = convertIpv6ArbitraryMaskToByteArray(statsIpv6MatchArbitraryBitMask.getIpv6SourceArbitraryBitmask());
348                     ipv6PrefixSource = createPrefix(statsIpv6MatchArbitraryBitMask.getIpv6SourceAddressNoMask(), srcByteMask);
349                 } else {
350                     ipv6PrefixSource = createPrefix(statsIpv6MatchArbitraryBitMask.getIpv6SourceAddressNoMask());
351                 }
352                 verdict = MatchComparatorHelper.compareIpv6PrefixNullSafe(ipv6PrefixSource, storedIpv6Match.getIpv6Source());
353             }
354         } else if (statsLayer3Match instanceof ArpMatch && storedLayer3Match instanceof ArpMatch) {
355             verdict = arpMatchEquals((ArpMatch)statsLayer3Match, (ArpMatch)storedLayer3Match);
356         } else {
357             final Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match);
358             if (nullCheckOut != null) {
359                 verdict = nullCheckOut;
360             } else {
361                 verdict = storedLayer3Match.equals(statsLayer3Match);
362             }
363         }
364         return verdict;
365     }
366
367     static boolean arpMatchEquals(final ArpMatch statsArpMatch, final ArpMatch storedArpMatch) {
368
369         Integer statsOp = statsArpMatch.getArpOp();
370         Integer storedOp = storedArpMatch.getArpOp();
371
372         Boolean nullCheck = checkNullValues(statsOp, storedOp);
373         if (nullCheck != null) {
374             if (nullCheck == false) {
375                 return false;
376             }
377         } else if (!statsOp.equals(storedOp)) {
378             return false;
379         }
380
381         Ipv4Prefix statsIp = statsArpMatch.getArpSourceTransportAddress();
382         Ipv4Prefix storedIp = storedArpMatch.getArpSourceTransportAddress();
383         if (!compareIpv4PrefixNullSafe(statsIp, storedIp)) {
384             return false;
385         }
386
387         statsIp = statsArpMatch.getArpTargetTransportAddress();
388         storedIp = storedArpMatch.getArpTargetTransportAddress();
389         if (!compareIpv4PrefixNullSafe(statsIp, storedIp)) {
390             return false;
391         }
392
393         MacAddressFilter statsMac = statsArpMatch.getArpSourceHardwareAddress();
394         MacAddressFilter storedMac = storedArpMatch.getArpSourceHardwareAddress();
395         if (!ethernetMatchFieldsEquals(statsMac, storedMac)) {
396             return false;
397         }
398
399         statsMac = statsArpMatch.getArpTargetHardwareAddress();
400         storedMac = storedArpMatch.getArpTargetHardwareAddress();
401         if (!ethernetMatchFieldsEquals(statsMac, storedMac)) {
402             return false;
403         }
404
405         return true;
406     }
407
408
409     /**
410      * TODO: why don't we use the default Ipv4Prefix.equals()?
411      *
412      * @param statsIpAddress
413      * @param storedIpAddress
414      * @return true if IPv4prefixes equals
415      */
416     static boolean IpAddressEquals(final Ipv4Prefix statsIpAddress, final Ipv4Prefix storedIpAddress) {
417         final IntegerIpAddress statsIpAddressInt = MatchComparatorHelper.strIpToIntIp(statsIpAddress.getValue());
418         final IntegerIpAddress storedIpAddressInt = MatchComparatorHelper.strIpToIntIp(storedIpAddress.getValue());
419
420         if (ipAndMaskBasedMatch(statsIpAddressInt, storedIpAddressInt)) {
421             return true;
422         }
423         if (ipBasedMatch(statsIpAddressInt, storedIpAddressInt)) {
424             return true;
425         }
426         return false;
427     }
428
429     static boolean ipAndMaskBasedMatch(final IntegerIpAddress statsIpAddressInt,
430                                        final IntegerIpAddress storedIpAddressInt) {
431         return ((statsIpAddressInt.getIp() & statsIpAddressInt.getMask()) == (storedIpAddressInt.getIp() & storedIpAddressInt
432                 .getMask()));
433     }
434
435     static boolean ipBasedMatch(final IntegerIpAddress statsIpAddressInt, final IntegerIpAddress storedIpAddressInt) {
436         return (statsIpAddressInt.getIp() == storedIpAddressInt.getIp());
437     }
438
439
440     private static boolean IpAddressEquals(Ipv6Prefix statsIpv6, Ipv6Prefix storedIpv6) {
441         final String[] statsIpMask = statsIpv6.getValue().split("/");
442         final String[] storedIpMask = storedIpv6.getValue().split("/");
443         if (! (statsIpMask.length > 1 && storedIpMask.length > 1 &&  statsIpMask[1].equals(storedIpMask[1]))){
444             return false;
445         }
446
447         final int prefix = Integer.parseInt(statsIpMask[1]);
448         final int byteIndex = prefix/BYTE_SIZE;
449         final int lastByteBits = BYTE_SIZE - (prefix % BYTE_SIZE);
450         final InetAddress statsIp = InetAddresses.forString(statsIpMask[0]);
451         final InetAddress storedIp = InetAddresses.forString(storedIpMask[0]);
452         byte[] statsIpArr = Arrays.copyOfRange(statsIp.getAddress(),0,byteIndex+1);
453         byte[] storedIpArr = Arrays.copyOfRange(storedIp.getAddress(),0,byteIndex+1);
454         statsIpArr[byteIndex] = (byte) (statsIpArr[byteIndex] & (0XFF << lastByteBits));
455         storedIpArr[byteIndex] = (byte) (storedIpArr[byteIndex] & (0XFF << lastByteBits));
456         if(Arrays.equals(statsIpArr,storedIpArr)) {
457             return true;
458         }
459         return false;
460     }
461
462     static Boolean checkNullValues(final Object v1, final Object v2) {
463         Boolean verdict = null;
464         if (v1 == null && v2 != null) {
465             verdict = Boolean.FALSE;
466         } else if (v1 != null && v2 == null) {
467             verdict = Boolean.FALSE;
468         } else if (v1 == null && v2 == null) {
469             verdict = Boolean.TRUE;
470         }
471         return verdict;
472     }
473
474     static boolean compareIpv4PrefixNullSafe(final Ipv4Prefix statsIpv4, final Ipv4Prefix storedIpv4) {
475         boolean verdict = true;
476         final Boolean checkDestNullValuesOut = checkNullValues(storedIpv4, statsIpv4);
477         if (checkDestNullValuesOut != null) {
478             verdict = checkDestNullValuesOut;
479         } else if (!IpAddressEquals(statsIpv4, storedIpv4)) {
480             verdict = false;
481         }
482         return verdict;
483     }
484
485     static boolean compareStringNullSafe(final String stringA, final String stringB) {
486         boolean verdict = true;
487         final Boolean checkDestNullValuesOut = checkNullValues(stringA,stringB);
488         if (checkDestNullValuesOut != null) {
489             verdict = checkDestNullValuesOut;
490         } else if (!stringA.equals(stringB)) {
491             verdict = false;
492         }
493         return verdict;
494     }
495
496     private static boolean compareIpv6PrefixNullSafe(Ipv6Prefix statsIpv6, Ipv6Prefix storedIpv6) {
497         boolean verdict = true;
498         final Boolean checkDestNullValuesOut = checkNullValues(statsIpv6, storedIpv6);
499         if (checkDestNullValuesOut != null) {
500             verdict = checkDestNullValuesOut;
501         } else if (!IpAddressEquals(statsIpv6, storedIpv6)) {
502             verdict = false;
503         }
504         return verdict;
505     }
506
507     /**
508      * Method return integer version of ip address. Converted int will be mask if mask specified
509      */
510     static IntegerIpAddress strIpToIntIp(final String ipAddresss) {
511
512         final String[] parts = ipAddresss.split("/");
513         final String ip = parts[0];
514         int prefix;
515
516         if (parts.length < 2) {
517             prefix = DEFAULT_SUBNET;
518         } else {
519             prefix = Integer.parseInt(parts[1]);
520             if (prefix < 0 || prefix > IPV4_MASK_LENGTH) {
521                 final StringBuilder stringBuilder = new StringBuilder(
522                         "Valid values for mask are from range 0 - 32. Value ");
523                 stringBuilder.append(prefix);
524                 stringBuilder.append(" is invalid.");
525                 throw new IllegalStateException(stringBuilder.toString());
526             }
527         }
528
529         IntegerIpAddress integerIpAddress = null;
530
531         final Inet4Address addr = ((Inet4Address) InetAddresses.forString(ip));
532         final byte[] addrBytes = addr.getAddress();
533         // FIXME: what is meaning of anding with 0xFF? Probably could be removed.
534         final int ipInt = ((addrBytes[POSITION_OCTET_1] & 0xFF) << SHIFT_OCTET_1)
535                 | ((addrBytes[POSITION_OCTET_2] & 0xFF) << SHIFT_OCTET_2)
536                 | ((addrBytes[POSITION_OCTET_3] & 0xFF) << SHIFT_OCTET_3)
537                 | ((addrBytes[POSITION_OCTET_4] & 0xFF) << SHIFT_OCTET_4);
538
539         // FIXME: Is this valid?
540         final int mask = 0xffffffff << DEFAULT_SUBNET - prefix;
541
542         integerIpAddress = new IntegerIpAddress(ipInt, mask);
543
544         return integerIpAddress;
545     }
546
547     static boolean isArbitraryBitMask(byte[] byteMask) {
548         if (byteMask == null) {
549             return false;
550         } else {
551             ArrayList<Integer> integerMaskArrayList = new ArrayList<Integer>();
552             String maskInBits;
553             // converting byte array to bits
554             maskInBits = new BigInteger(1, byteMask).toString(2);
555             ArrayList<String> stringMaskArrayList = new ArrayList<String>(Arrays.asList(maskInBits.split("(?!^)")));
556             for(String string:stringMaskArrayList){
557                 integerMaskArrayList.add(Integer.parseInt(string));
558             }
559             return checkArbitraryBitMask(integerMaskArrayList);
560         }
561     }
562
563     static boolean checkArbitraryBitMask(ArrayList<Integer> arrayList) {
564         if (arrayList.size()>0 && arrayList.size()< IPV4_MASK_LENGTH ) {
565             // checks 0*1* case - Leading zeros in arrayList are truncated
566             return true;
567         } else {
568             //checks 1*0*1 case
569             for(int i=0; i<arrayList.size()-1;i++) {
570                 if(arrayList.get(i) ==0 && arrayList.get(i+1) == 1) {
571                     return true;
572                 }
573             }
574         }
575         return false;
576     }
577
578     static final byte[] convertArbitraryMaskToByteArray(DottedQuad mask) {
579         String maskValue;
580         if (mask.getValue() != null) {
581             maskValue  = mask.getValue();
582         } else {
583             maskValue = DEFAULT_ARBITRARY_BIT_MASK;
584         }
585         InetAddress maskInIpFormat = null;
586         try {
587             maskInIpFormat = InetAddress.getByName(maskValue);
588         } catch (UnknownHostException e) {
589             LOG.error("Failed to recognize the host while converting mask ", e);
590         }
591         byte[] bytes = maskInIpFormat.getAddress();
592         return bytes;
593     }
594
595     private static final byte[] convertIpv6ArbitraryMaskToByteArray ( final Ipv6ArbitraryMask mask) {
596         String maskValue;
597         if (mask.getValue() != null) {
598             maskValue = mask.getValue();
599         } else {
600             maskValue = DEFAULT_IPV6_ARBITRARY_BIT_MASK;
601         }
602         InetAddress maskInIpv6Format = null;
603         try {
604             maskInIpv6Format = InetAddress.getByName(maskValue);
605         } catch (UnknownHostException e) {
606             LOG.error("Failed to convert string mask value to ipv6 format ", e);
607         }
608         return maskInIpv6Format.getAddress();
609     }
610
611     static String normalizeIpv4Address(Ipv4Address ipAddress, DottedQuad netMask) {
612         String actualIpAddress="";
613         String[] netMaskParts = netMask.getValue().split("\\.");
614         String[] ipAddressParts = ipAddress.getValue().split("\\.");
615
616         for (int i=0; i<ipAddressParts.length;i++) {
617             int integerFormatIpAddress=Integer.parseInt(ipAddressParts[i]);
618             int integerFormatNetMask=Integer.parseInt(netMaskParts[i]);
619             int ipAddressPart=(integerFormatIpAddress) & (integerFormatNetMask);
620             actualIpAddress += ipAddressPart;
621             if (i != ipAddressParts.length -1 ) {
622                 actualIpAddress = actualIpAddress+".";
623             }
624         }
625         return actualIpAddress;
626     }
627
628     private static String normalizeIpv6Address(final Ipv6Address ipAddress, final Ipv6ArbitraryMask netMask) {
629         byte[] ipAddressParts = convertIpv6ToBytes(ipAddress.getValue());
630         byte[] netMaskParts  = convertIpv6ToBytes(netMask.getValue());
631         byte[] actualIpv6Bytes = new byte[16];
632
633         for (int i=0; i<ipAddressParts.length;i++) {
634             byte ipAddressPart= (byte) (ipAddressParts[i] & netMaskParts[i]);
635             actualIpv6Bytes[i] = ipAddressPart;
636         }
637         InetAddress ipv6Address = null;
638         try {
639             ipv6Address = InetAddress.getByAddress(actualIpv6Bytes);
640         } catch (UnknownHostException e) {
641             LOG.error("Failed to recognize the host while normalizing IPv6 address from bytes ", e);
642         }
643         return ipv6Address.getHostAddress();
644     }
645
646     private static byte[] convertIpv6ToBytes(final String ipv6Address) {
647         return extractIpv6CanonicalForm(ipv6Address).getAddress();
648     }
649
650     private static InetAddress extractIpv6CanonicalForm(final String ipv6Address) {
651         InetAddress address = null;
652         try {
653             address = InetAddress.getByName(ipv6Address);
654         } catch (UnknownHostException e) {
655             LOG.error("Failed to recognize the host while converting IPv6 to bytes ", e);
656         }
657         return address;
658     }
659
660     static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final byte [] bytemask){
661         return createPrefix(ipv4Address, String.valueOf(countBits(bytemask)));
662     }
663
664     private static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final byte [] bytemask) {
665         return createPrefix(ipv6Address, String.valueOf(countBits(bytemask)));
666     }
667
668     private static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final String mask) {
669         if (mask != null && !mask.isEmpty()) {
670             return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + mask);
671         } else {
672             return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + IPV6_ADDRESS_LENGTH);
673         }
674     }
675
676     private static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address) {
677         return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + IPV6_ADDRESS_LENGTH);
678     }
679
680     static int countBits(final byte[] mask) {
681         int netmask = 0;
682         for (byte b : mask) {
683             netmask += Integer.bitCount(UnsignedBytes.toInt(b));
684         }
685         return netmask;
686     }
687
688     static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address){
689         return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + IPV4_ADDRESS_LENGTH);
690     }
691
692     static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final String mask){
693         /*
694          * Ipv4Address has already validated the address part of the prefix,
695          * It is mandated to comply to the same regexp as the address
696          * There is absolutely no point rerunning additional checks vs this
697          * Note - there is no canonical form check here!!!
698          */
699         if (null != mask && !mask.isEmpty()) {
700             return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + mask);
701         } else {
702             return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + IPV4_ADDRESS_LENGTH);
703         }
704     }
705 }