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