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.io.Serializable;
13 import java.net.Inet4Address;
14 import java.net.Inet6Address;
15 import java.net.InetAddress;
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.List;
22 import java.util.Map.Entry;
24 import javax.xml.bind.annotation.XmlAccessType;
25 import javax.xml.bind.annotation.XmlAccessorType;
26 import javax.xml.bind.annotation.XmlElement;
27 import javax.xml.bind.annotation.XmlRootElement;
29 import org.apache.commons.lang3.builder.EqualsBuilder;
30 import org.apache.commons.lang3.builder.HashCodeBuilder;
31 import org.opendaylight.controller.sal.utils.EtherTypes;
32 import org.opendaylight.controller.sal.utils.IPProtocols;
33 import org.opendaylight.controller.sal.utils.NetUtils;
36 * Represents the generic match criteria for a network frame/packet/message
37 * It contains a collection of individual field match
41 @XmlAccessorType(XmlAccessType.NONE)
42 public class Match implements Cloneable, Serializable {
43 private static final long serialVersionUID = 1L;
44 private static final Map<MatchType, MatchType> reversableMatches;
46 Map<MatchType, MatchType> map = new HashMap<MatchType, MatchType>();
47 map.put(MatchType.DL_SRC, MatchType.DL_DST);
48 map.put(MatchType.DL_DST, MatchType.DL_SRC);
49 map.put(MatchType.NW_SRC, MatchType.NW_DST);
50 map.put(MatchType.NW_DST, MatchType.NW_SRC);
51 map.put(MatchType.TP_SRC, MatchType.TP_DST);
52 map.put(MatchType.TP_DST, MatchType.TP_SRC);
53 reversableMatches = Collections.unmodifiableMap(map);
55 private Map<MatchType, MatchField> fields;
56 private int matches; // concise way to tell which fields the match is set for (may remove if not needed)
59 fields = new HashMap<MatchType, MatchField>();
63 public Match(Match match) {
64 fields = new HashMap<MatchType, MatchField>(match.fields);
65 matches = match.matches;
69 * Generic setter for frame/packet/message's header fields against which to match
70 * Note: For MAC addresses, please pass the cloned value to this function
72 * @param type packet's header field type
73 * @param value field's value to assign to the match
74 * @param mask field's bitmask to apply to the match (has to be of the same class type of value)
76 public void setField(MatchType type, Object value, Object mask) {
77 MatchField field = new MatchField(type, value, mask);
78 if (field.isValid()) {
79 fields.put(type, field);
80 matches |= type.getIndex();
85 * Generic setter for frame/packet/message's header fields against which to match
86 * Note: For MAC addresses, please pass the cloned value to this function
88 * @param type packet's header field type
89 * @param value field's value to assign to the match
91 public void setField(MatchType type, Object value) {
92 MatchField field = new MatchField(type, value);
93 if (field.isValid()) {
94 fields.put(type, field);
95 matches |= type.getIndex();
100 * Generic setter for frame/packet/message's header field against which to match
102 * @param field the fields parameters as MAtchField object
104 public void setField(MatchField field) {
105 if (field.isValid()) {
106 fields.put(field.getType(), field);
107 matches |= field.getType().getIndex();
112 * Generic method to clear a field from the match
114 public void clearField(MatchType type) {
116 matches &= ~type.getIndex();
120 * Generic getter for fields against which the match is programmed
122 * @param type frame/packet/message's header field type
125 public MatchField getField(MatchType type) {
126 return fields.get(type);
130 * Returns the fields the match is set for in a bitmask fashion
131 * Each bit represents a field the match is configured for
133 * @return the 32 bit long mask (Refer to {@code}org.opendaylight.controller.sal.match.MatchElement)
135 public int getMatches() {
140 * Returns the list of MatchType fields the match is set for
142 * @return List of individual MatchType fields.
144 public List<MatchType> getMatchesList() {
145 return new ArrayList<MatchType>(fields.keySet());
149 * Returns the list of MatchFields the match is set for
151 * @return List of individual MatchField values.
153 @XmlElement(name="matchField")
154 public List<MatchField> getMatchFields() {
155 return new ArrayList<MatchField>(fields.values());
159 * Returns whether this match is for an IPv6 flow
161 public boolean isIPv6() {
162 return (isPresent(MatchType.DL_TYPE)
163 && ((Short) getField(MatchType.DL_TYPE).getValue())
164 .equals(EtherTypes.IPv6.shortValue())
165 || isPresent(MatchType.NW_PROTO)
166 && ((Byte) getField(MatchType.NW_PROTO).getValue())
167 .equals(IPProtocols.IPV6ICMP.byteValue())
168 || isPresent(MatchType.NW_SRC)
169 && getField(MatchType.NW_SRC).getValue() instanceof Inet6Address || isPresent(MatchType.NW_DST)
170 && getField(MatchType.NW_DST).getValue() instanceof Inet6Address);
174 * Returns whether this match is for an IPv4 flow
176 public boolean isIPv4() {
181 * Returns whether for the specified field type the match is to be considered "any"
182 * Equivalent to say this match does not care about the value of the specified field
187 public boolean isAny(MatchType type) {
188 //return ((fields.get(type) == null) || (fields.get(type).getBitMask() == 0L));
189 return !fields.containsKey(type);
193 * Returns whether a match for the specified field type is configured
198 public boolean isPresent(MatchType type) {
199 return (fields.get(type) != null);
203 public Match clone() {
206 cloned = (Match) super.clone();
207 cloned.fields = new HashMap<MatchType, MatchField>();
208 for (Entry<MatchType, MatchField> entry : this.fields.entrySet()) {
209 cloned.fields.put(entry.getKey(), entry.getValue().clone());
211 } catch (CloneNotSupportedException e) {
212 throw new RuntimeException(e);
218 * Returns a reversed version of this match
219 * For example, in the reversed version the network source and destination
220 * addresses will be exchanged. Non symmetric match field will not be
221 * copied over into the reversed match version, like input port.
225 public Match reverse() {
226 // Copy over all fields
227 Match reverse = this.clone();
229 // Flip symmetric fields
230 for (Map.Entry<MatchType, MatchType> entry : Match.reversableMatches
232 MatchType from = entry.getKey();
233 MatchType to = entry.getValue();
234 if (this.isPresent(from)) {
235 reverse.setField(to, this.getField(from).getValue(), this
236 .getField(from).getMask());
240 // Reset asymmetric fields
241 reverse.clearField(MatchType.IN_PORT);
247 * Check whether the current match conflicts with the passed filter match
248 * This match conflicts with the filter if for at least a MatchType defined
249 * in the filter match, the respective MatchFields differ or are not compatible
251 * For example, Let's suppose the filter has the following MatchFields:
253 * NW_DST = 172.20.30.110/24
255 * while this match has the following MatchFields:
256 * NW_DST = 172.20.30.45/24
259 * Then the function would return false as the two Match are not conflicting
261 * Note: the mask value is taken into account only for MatchType.NW_SRC and MatchType.NW_DST
263 * @param match the MAtch describing the filter
264 * @return true if the match is conflicting with the filter, false otherwise
266 public boolean conflictWithFilter(Match filter) {
267 // Iterate through the MatchType defined in the filter
268 for (MatchType type : filter.getMatchesList()) {
269 if (this.isAny(type)) {
273 MatchField thisField = this.getField(type);
274 MatchField filterField = filter.getField(type);
279 if (Arrays.equals((byte[]) thisField.getValue(),
280 (byte[]) filterField.getValue())) {
286 InetAddress thisAddress = (InetAddress) thisField.getValue();
287 InetAddress filterAddress = (InetAddress) filterField
290 if (thisAddress instanceof Inet4Address
291 && filterAddress instanceof Inet6Address
292 || thisAddress instanceof Inet6Address
293 && filterAddress instanceof Inet4Address) {
296 InetAddress thisMask = (InetAddress) thisField.getMask();
297 InetAddress filterMask = (InetAddress) filterField.getMask();
298 // thisAddress has to be in same subnet of filterAddress
299 if (NetUtils.inetAddressConflict(thisAddress, filterAddress,
300 thisMask, filterMask)) {
305 if (!thisField.getValue().equals(filterField.getValue())) {
309 //TODO: check v4 v6 incompatibility
315 * Merge the current Match fields with the fields of the filter Match
316 * A check is first run to see if this Match is compatible with the
317 * filter Match. If it is not, the merge is not attempted.
323 public Match mergeWithFilter(Match filter) {
324 if (!this.conflictWithFilter(filter)) {
326 * No conflict with the filter
327 * We can copy over the fields which this match does not have
329 for (MatchType type : filter.getMatchesList()) {
330 if (this.isAny(type)) {
331 this.setField(filter.getField(type).clone());
339 public int hashCode() {
340 return HashCodeBuilder.reflectionHashCode(this);
344 public boolean equals(Object obj) {
345 return EqualsBuilder.reflectionEquals(this, obj);
349 public String toString() {
350 return "Match[" + fields.values() + "]";