2 * Copyright (c) 2013, 2015 IBM Corporation and others. All rights reserved.
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
9 package org.opendaylight.openflowplugin.impl.util;
11 import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
12 import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
13 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
15 import java.util.ArrayList;
16 import java.util.Collection;
19 * Provides comparator for comparing according to various {@link Match} attributes
22 public final class MatchComparatorFactory {
24 private MatchComparatorFactory() {
28 private static final Collection<SimpleComparator<Match>> MATCH_COMPARATORS = new ArrayList<>();
30 MATCH_COMPARATORS.add(MatchComparatorFactory.createEthernet());
31 MATCH_COMPARATORS.add(MatchComparatorFactory.createIcmpv4());
32 MATCH_COMPARATORS.add(MatchComparatorFactory.createInPhyPort());
33 MATCH_COMPARATORS.add(MatchComparatorFactory.createInPort());
34 MATCH_COMPARATORS.add(MatchComparatorFactory.createIp());
35 MATCH_COMPARATORS.add(MatchComparatorFactory.createL3());
36 MATCH_COMPARATORS.add(MatchComparatorFactory.createL4());
37 MATCH_COMPARATORS.add(MatchComparatorFactory.createProtocolMatchFields());
38 MATCH_COMPARATORS.add(MatchComparatorFactory.createMetadata());
39 MATCH_COMPARATORS.add(MatchComparatorFactory.createNull());
40 MATCH_COMPARATORS.add(MatchComparatorFactory.createTunnel());
41 MATCH_COMPARATORS.add(MatchComparatorFactory.createVlan());
44 public static SimpleComparator<Match> createNull() {
45 return new SimpleComparator<Match>() {
47 * Comparation by whole object
50 public boolean areObjectsEqual(short version, Match statsMatch, Match storedMatch) {
51 return (statsMatch == null) == (storedMatch == null);
56 public static SimpleComparator<Match> createVlan() {
57 return new SimpleComparator<Match>() {
62 public boolean areObjectsEqual(short version, Match statsMatch, Match storedMatch) {
63 if (storedMatch == null) {
66 if (storedMatch.getVlanMatch() == null) {
67 if (statsMatch.getVlanMatch() != null) {
70 } else if (!storedMatch.getVlanMatch().equals(statsMatch.getVlanMatch())) {
78 public static SimpleComparator<Match> createTunnel() {
79 return new SimpleComparator<Match>() {
81 * Comparation by tunnel
84 public boolean areObjectsEqual(short version, Match statsMatch, Match storedMatch) {
85 if (storedMatch == null) {
88 if (storedMatch.getTunnel() == null) {
89 if (statsMatch.getTunnel() != null) {
92 } else if (!storedMatch.getTunnel().equals(statsMatch.getTunnel())) {
100 public static SimpleComparator<Match> createProtocolMatchFields() {
101 return new SimpleComparator<Match>() {
103 * Comparation by protocol fields
106 public boolean areObjectsEqual(short version, Match statsMatch, Match storedMatch) {
107 if (storedMatch == null) {
110 if (storedMatch.getProtocolMatchFields() == null) {
111 if (statsMatch.getProtocolMatchFields() != null) {
114 } else if (!storedMatch.getProtocolMatchFields().equals(statsMatch.getProtocolMatchFields())) {
122 public static SimpleComparator<Match> createMetadata() {
123 return new SimpleComparator<Match>() {
125 * Comparation by metadata
128 public boolean areObjectsEqual(short version, Match statsMatch, Match storedMatch) {
129 if (storedMatch == null) {
132 if (storedMatch.getMetadata() == null) {
133 if (statsMatch.getMetadata() != null) {
136 } else if (!storedMatch.getMetadata().equals(statsMatch.getMetadata())) {
144 public static SimpleComparator<Match> createL4() {
145 return new SimpleComparator<Match>() {
147 * Comparation by layer4
150 public boolean areObjectsEqual(short version, Match statsMatch, Match storedMatch) {
151 if (storedMatch == null) {
154 if (storedMatch.getLayer4Match() == null) {
155 if (statsMatch.getLayer4Match() != null) {
158 } else if (!storedMatch.getLayer4Match().equals(statsMatch.getLayer4Match())) {
166 public static SimpleComparator<Match> createL3() {
167 return new SimpleComparator<Match>() {
169 * Comparation by layer3
172 public boolean areObjectsEqual(short version, Match statsMatch, Match storedMatch) {
173 if (storedMatch == null) {
176 if (storedMatch.getLayer3Match() == null) {
177 if (statsMatch.getLayer3Match() != null) {
180 } else if (!MatchComparatorHelper.layer3MatchEquals(statsMatch.getLayer3Match(), storedMatch.getLayer3Match())) {
188 public static SimpleComparator<Match> createIp() {
189 return new SimpleComparator<Match>() {
194 public boolean areObjectsEqual(short version, Match statsMatch, Match storedMatch) {
195 if (storedMatch == null) {
198 if (storedMatch.getIpMatch() == null) {
199 if (statsMatch.getIpMatch() != null) {
202 } else if (!storedMatch.getIpMatch().equals(statsMatch.getIpMatch())) {
212 * Converts both ports in node connector id format to number format and compare them
214 * @param version openflow version
215 * @param left first object to compare
216 * @param right second object to compare
217 * @return true if equal
219 private static boolean arePortNumbersEqual(short version, NodeConnectorId left, NodeConnectorId right) {
220 final OpenflowVersion ofVersion = OpenflowVersion.get(version);
222 final Long leftPort = InventoryDataServiceUtil.portNumberfromNodeConnectorId(ofVersion, left);
223 final Long rightPort = InventoryDataServiceUtil.portNumberfromNodeConnectorId(ofVersion, right);
225 if (leftPort == null) {
226 if (rightPort != null) {
229 } else if (!leftPort.equals(rightPort)) {
236 public static SimpleComparator<Match> createInPort() {
237 return new SimpleComparator<Match>() {
239 * Comparation by InPort
242 public boolean areObjectsEqual(short version, Match statsMatch, Match storedMatch) {
243 if (storedMatch == null) {
246 if (storedMatch.getInPort() == null) {
247 if (statsMatch.getInPort() != null) {
250 } else if (!arePortNumbersEqual(version, storedMatch.getInPort(), statsMatch.getInPort())) {
258 public static SimpleComparator<Match> createInPhyPort() {
259 return new SimpleComparator<Match>() {
261 * Comparation by InPhyPort
264 public boolean areObjectsEqual(short version, Match statsMatch, Match storedMatch) {
265 if (storedMatch == null) {
268 if (storedMatch.getInPhyPort() == null) {
269 if (statsMatch.getInPhyPort() != null) {
272 } else if (!arePortNumbersEqual(version, storedMatch.getInPhyPort(), statsMatch.getInPhyPort())) {
280 public static SimpleComparator<Match> createEthernet() {
281 return new SimpleComparator<Match>() {
283 * Comparation by Ethernet
286 public boolean areObjectsEqual(short version, Match statsMatch, Match storedMatch) {
287 if (storedMatch == null) {
290 if (storedMatch.getEthernetMatch() == null) {
291 if (statsMatch.getEthernetMatch() != null) {
294 } else if (!MatchComparatorHelper.ethernetMatchEquals(statsMatch.getEthernetMatch(), storedMatch.getEthernetMatch())) {
302 public static SimpleComparator<Match> createIcmpv4() {
303 return new SimpleComparator<Match>() {
305 * Comparation by Icmpv4
308 public boolean areObjectsEqual(short version, Match statsMatch, Match storedMatch) {
309 if (storedMatch == null) {
312 if (storedMatch.getIcmpv4Match() == null) {
313 if (statsMatch.getIcmpv4Match() != null) {
316 } else if (!storedMatch.getIcmpv4Match().equals(statsMatch.getIcmpv4Match())) {
324 public static SimpleComparator<Match> createMatch() {
325 return new SimpleComparator<Match>() {
327 * Compares flows by whole match
330 public boolean areObjectsEqual(short version, final Match statsFlow, final Match storedFlow) {
331 if (statsFlow == null) {
332 if (storedFlow != null) {
335 } else if (!compareMatches(version, statsFlow, storedFlow)) {
345 * Explicit equals method to compare the 'match' for flows stored in the data-stores and flow fetched from the switch.
346 * Flow installation process has three steps
347 * 1) Store flow in config data store
348 * 2) and send it to plugin for installation
349 * 3) Flow gets installed in switch
351 * The flow user wants to install and what finally gets installed in switch can be slightly different.
352 * E.g, If user installs flow with src/dst ip=10.0.0.1/24, when it get installed in the switch
353 * src/dst ip will be changes to 10.0.0.0/24 because of netmask of 24. When statistics manager fetch
354 * stats it gets 10.0.0.0/24 rather then 10.0.0.1/24. Custom match takes care of by using masked ip
355 * while comparing two ip addresses.
357 * Sometimes when user don't provide few values that is required by flow installation request, like
358 * priority,hard timeout, idle timeout, cookies etc, plugin usages default values before sending
359 * request to the switch. So when statistics manager gets flow statistics, it gets the default value.
360 * But the flow stored in config data store don't have those defaults value. I included those checks
361 * in the customer flow/match equal function.
368 private static boolean compareMatches(final short version, final Match statsMatch, final Match storedMatch) {
369 if (statsMatch == storedMatch) {
373 for (SimpleComparator<Match> matchComp : MATCH_COMPARATORS) {
374 if (!matchComp.areObjectsEqual(version, statsMatch, storedMatch)) {