3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
10 package org.opendaylight.controller.sal.match;
12 import java.net.Inet4Address;
13 import java.net.Inet6Address;
14 import java.net.InetAddress;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Collections;
18 import java.util.HashMap;
19 import java.util.List;
21 import java.util.Map.Entry;
23 import javax.xml.bind.annotation.XmlAccessType;
24 import javax.xml.bind.annotation.XmlAccessorType;
25 import javax.xml.bind.annotation.XmlElement;
26 import javax.xml.bind.annotation.XmlRootElement;
28 import org.apache.commons.lang3.builder.EqualsBuilder;
29 import org.apache.commons.lang3.builder.HashCodeBuilder;
30 import org.opendaylight.controller.sal.utils.EtherTypes;
31 import org.opendaylight.controller.sal.utils.IPProtocols;
32 import org.opendaylight.controller.sal.utils.NetUtils;
35 * Represents the generic match criteria for a network frame/packet/message
36 * It contains a collection of individual field match
40 @XmlAccessorType(XmlAccessType.NONE)
41 public class Match implements Cloneable {
42 private static final Map<MatchType, MatchType> reversableMatches;
44 Map<MatchType, MatchType> map = new HashMap<MatchType, MatchType>();
45 map.put(MatchType.DL_SRC, MatchType.DL_DST);
46 map.put(MatchType.DL_DST, MatchType.DL_SRC);
47 map.put(MatchType.NW_SRC, MatchType.NW_DST);
48 map.put(MatchType.NW_DST, MatchType.NW_SRC);
49 map.put(MatchType.TP_SRC, MatchType.TP_DST);
50 map.put(MatchType.TP_DST, MatchType.TP_SRC);
51 reversableMatches = Collections.unmodifiableMap(map);
53 private Map<MatchType, MatchField> fields;
54 private int matches; // concise way to tell which fields the match is set for (may remove if not needed)
57 fields = new HashMap<MatchType, MatchField>();
61 public Match(Match match) {
62 fields = new HashMap<MatchType, MatchField>(match.fields);
63 matches = match.matches;
67 * Generic setter for frame/packet/message's header fields against which to match
68 * Note: For MAC addresses, please pass the cloned value to this function
70 * @param type packet's header field type
71 * @param value field's value to assign to the match
72 * @param mask field's bitmask to apply to the match (has to be of the same class type of value)
74 public void setField(MatchType type, Object value, Object mask) {
75 MatchField field = new MatchField(type, value, mask);
76 if (field.isValid()) {
77 fields.put(type, field);
78 matches |= type.getIndex();
83 * Generic setter for frame/packet/message's header fields against which to match
84 * Note: For MAC addresses, please pass the cloned value to this function
86 * @param type packet's header field type
87 * @param value field's value to assign to the match
89 public void setField(MatchType type, Object value) {
90 MatchField field = new MatchField(type, value);
91 if (field.isValid()) {
92 fields.put(type, field);
93 matches |= type.getIndex();
98 * Generic setter for frame/packet/message's header field against which to match
100 * @param field the fields parameters as MAtchField object
102 public void setField(MatchField field) {
103 if (field.isValid()) {
104 fields.put(field.getType(), field);
105 matches |= field.getType().getIndex();
110 * Generic method to clear a field from the match
112 public void clearField(MatchType type) {
114 matches &= ~type.getIndex();
118 * Generic getter for fields against which the match is programmed
120 * @param type frame/packet/message's header field type
123 public MatchField getField(MatchType type) {
124 return fields.get(type);
128 * Returns the fields the match is set for in a bitmask fashion
129 * Each bit represents a field the match is configured for
131 * @return the 32 bit long mask (Refer to {@code}org.opendaylight.controller.sal.match.MatchElement)
134 public int getMatches() {
139 * Returns the list of MatchType fields the match is set for
141 * @return List of individual MatchType fields.
143 public List<MatchType> getMatchesList() {
144 return new ArrayList<MatchType>(fields.keySet());
148 * Returns whether this match is for an IPv6 flow
150 public boolean isIPv6() {
151 return (isPresent(MatchType.DL_TYPE)
152 && ((Short) getField(MatchType.DL_TYPE).getValue())
153 .equals(EtherTypes.IPv6.shortValue())
154 || isPresent(MatchType.NW_PROTO)
155 && ((Byte) getField(MatchType.NW_PROTO).getValue())
156 .equals(IPProtocols.IPV6ICMP.byteValue())
157 || isPresent(MatchType.NW_SRC)
158 && getField(MatchType.NW_SRC).getValue() instanceof Inet6Address || isPresent(MatchType.NW_DST)
159 && getField(MatchType.NW_DST).getValue() instanceof Inet6Address);
163 * Returns whether this match is for an IPv4 flow
165 public boolean isIPv4() {
170 * Returns whether for the specified field type the match is to be considered "any"
171 * Equivalent to say this match does not care about the value of the specified field
176 public boolean isAny(MatchType type) {
177 //return ((fields.get(type) == null) || (fields.get(type).getBitMask() == 0L));
178 return !fields.containsKey(type);
182 * Returns whether a match for the specified field type is configured
187 public boolean isPresent(MatchType type) {
188 return (fields.get(type) != null);
192 public Match clone() {
195 cloned = (Match) super.clone();
196 cloned.fields = new HashMap<MatchType, MatchField>();
197 for (Entry<MatchType, MatchField> entry : this.fields.entrySet()) {
198 cloned.fields.put(entry.getKey(), entry.getValue().clone());
200 } catch (CloneNotSupportedException e) {
201 throw new RuntimeException(e);
207 * Returns a reversed version of this match
208 * For example, in the reversed version the network source and destination
209 * addresses will be exchanged. Non symmetric match field will not be
210 * copied over into the reversed match version, like input port.
214 public Match reverse() {
215 // Copy over all fields
216 Match reverse = this.clone();
218 // Flip symmetric fields
219 for (Map.Entry<MatchType, MatchType> entry : Match.reversableMatches
221 MatchType from = entry.getKey();
222 MatchType to = entry.getValue();
223 if (this.isPresent(from)) {
224 reverse.setField(to, this.getField(from).getValue(), this
225 .getField(from).getMask());
229 // Reset asymmetric fields
230 reverse.clearField(MatchType.IN_PORT);
236 * Check whether the current match conflicts with the passed filter match
237 * This match conflicts with the filter if for at least a MatchType defined
238 * in the filter match, the respective MatchFields differ or are not compatible
240 * For example, Let's suppose the filter has the following MatchFields:
242 * NW_DST = 172.20.30.110/24
244 * while this match has the following MatchFields:
245 * NW_DST = 172.20.30.45/24
248 * Then the function would return false as the two Match are not conflicting
250 * Note: the mask value is taken into account only for MatchType.NW_SRC and MatchType.NW_DST
252 * @param match the MAtch describing the filter
253 * @return true if the match is conflicting with the filter, false otherwise
255 public boolean conflictWithFilter(Match filter) {
256 // Iterate through the MatchType defined in the filter
257 for (MatchType type : filter.getMatchesList()) {
258 if (this.isAny(type)) {
262 MatchField thisField = this.getField(type);
263 MatchField filterField = filter.getField(type);
268 if (Arrays.equals((byte[]) thisField.getValue(),
269 (byte[]) filterField.getValue())) {
275 InetAddress thisAddress = (InetAddress) thisField.getValue();
276 InetAddress filterAddress = (InetAddress) filterField
279 if (thisAddress instanceof Inet4Address
280 && filterAddress instanceof Inet6Address
281 || thisAddress instanceof Inet6Address
282 && filterAddress instanceof Inet4Address) {
285 InetAddress thisMask = (InetAddress) filter.getField(type)
287 InetAddress filterMask = (InetAddress) filter.getField(type)
289 // thisAddress has to be in same subnet of filterAddress
290 if (NetUtils.inetAddressConflict(thisAddress, filterAddress,
291 thisMask, filterMask)) {
296 if (!thisField.getValue().equals(filterField.getValue())) {
300 //TODO: check v4 v6 incompatibility
306 * Merge the current Match fields with the fields of the filter Match
307 * A check is first run to see if this Match is compatible with the
308 * filter Match. If it is not, the merge is not attempted.
314 public Match mergeWithFilter(Match filter) {
315 if (!this.conflictWithFilter(filter)) {
317 * No conflict with the filter
318 * We can copy over the fields which this match does not have
320 for (MatchType type : filter.getMatchesList()) {
321 if (this.isAny(type)) {
322 this.setField(filter.getField(type).clone());
330 public int hashCode() {
331 return HashCodeBuilder.reflectionHashCode(this);
335 public boolean equals(Object obj) {
336 return EqualsBuilder.reflectionEquals(this, obj);
340 public String toString() {
341 return "Match[" + fields.values() + "]";