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.opendaylight.controller.sal.utils.EtherTypes;
30 import org.opendaylight.controller.sal.utils.IPProtocols;
31 import org.opendaylight.controller.sal.utils.NetUtils;
34 * Represents the generic match criteria for a network frame/packet/message
35 * It contains a collection of individual field match
39 @XmlAccessorType(XmlAccessType.NONE)
40 public class Match implements Cloneable, Serializable {
41 private static final long serialVersionUID = 1L;
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)
133 public int getMatches() {
138 * Returns the list of MatchType fields the match is set for
140 * @return List of individual MatchType fields.
142 public List<MatchType> getMatchesList() {
143 return new ArrayList<MatchType>(fields.keySet());
147 * Returns the list of MatchFields the match is set for
149 * @return List of individual MatchField values.
151 @XmlElement(name="matchField")
152 public List<MatchField> getMatchFields() {
153 return new ArrayList<MatchField>(fields.values());
157 * Returns whether this match is for an IPv6 flow
159 public boolean isIPv6() {
160 return (isPresent(MatchType.DL_TYPE)
161 && ((Short) getField(MatchType.DL_TYPE).getValue())
162 .equals(EtherTypes.IPv6.shortValue())
163 || isPresent(MatchType.NW_PROTO)
164 && ((Byte) getField(MatchType.NW_PROTO).getValue())
165 .equals(IPProtocols.IPV6ICMP.byteValue())
166 || isPresent(MatchType.NW_SRC)
167 && getField(MatchType.NW_SRC).getValue() instanceof Inet6Address || isPresent(MatchType.NW_DST)
168 && getField(MatchType.NW_DST).getValue() instanceof Inet6Address);
172 * Returns whether this match is for an IPv4 flow
174 public boolean isIPv4() {
179 * Returns whether for the specified field type the match is to be considered "any"
180 * Equivalent to say this match does not care about the value of the specified field
185 public boolean isAny(MatchType type) {
186 //return ((fields.get(type) == null) || (fields.get(type).getBitMask() == 0L));
187 return !fields.containsKey(type);
191 * Returns whether a match for the specified field type is configured
196 public boolean isPresent(MatchType type) {
197 return (fields.get(type) != null);
201 public Match clone() {
204 cloned = (Match) super.clone();
205 cloned.fields = new HashMap<MatchType, MatchField>();
206 for (Entry<MatchType, MatchField> entry : this.fields.entrySet()) {
207 cloned.fields.put(entry.getKey(), entry.getValue().clone());
209 } catch (CloneNotSupportedException e) {
210 throw new RuntimeException(e);
216 * Returns a reversed version of this match
217 * For example, in the reversed version the network source and destination
218 * addresses will be exchanged. Non symmetric match field will not be
219 * copied over into the reversed match version, like input port.
223 public Match reverse() {
224 // Copy over all fields
225 Match reverse = this.clone();
227 // Flip symmetric fields
228 for (Map.Entry<MatchType, MatchType> entry : Match.reversableMatches.entrySet()) {
229 MatchType from = entry.getKey();
230 MatchType to = entry.getValue();
231 if (this.isPresent(from)) {
232 reverse.setField(to, this.getField(from).getValue(), this.getField(from).getMask());
233 if (!this.isPresent(to)) {
234 reverse.clearField(from);
239 // Reset asymmetric fields
240 reverse.clearField(MatchType.IN_PORT);
246 * Check whether the current match conflicts with the passed filter match
247 * This match conflicts with the filter if for at least a MatchType defined
248 * in the filter match, the respective MatchFields differ or are not compatible
250 * For example, Let's suppose the filter has the following MatchFields:
252 * NW_DST = 172.20.30.110/24
254 * while this match has the following MatchFields:
255 * NW_DST = 172.20.30.45/24
258 * Then the function would return false as the two Match are not conflicting
260 * Note: the mask value is taken into account only for MatchType.NW_SRC and MatchType.NW_DST
262 * @param match the MAtch describing the filter
263 * @return true if the match is conflicting with the filter, false otherwise
265 public boolean conflictWithFilter(Match filter) {
266 // Iterate through the MatchType defined in the filter
267 for (MatchType type : filter.getMatchesList()) {
268 if (this.isAny(type)) {
272 MatchField thisField = this.getField(type);
273 MatchField filterField = filter.getField(type);
278 if (Arrays.equals((byte[]) thisField.getValue(),
279 (byte[]) filterField.getValue())) {
285 InetAddress thisAddress = (InetAddress) thisField.getValue();
286 InetAddress filterAddress = (InetAddress) filterField
289 if (thisAddress instanceof Inet4Address
290 && filterAddress instanceof Inet6Address
291 || thisAddress instanceof Inet6Address
292 && filterAddress instanceof Inet4Address) {
295 InetAddress thisMask = (InetAddress) thisField.getMask();
296 InetAddress filterMask = (InetAddress) filterField.getMask();
297 // thisAddress has to be in same subnet of filterAddress
298 if (NetUtils.inetAddressConflict(thisAddress, filterAddress,
299 thisMask, filterMask)) {
304 if (!thisField.getValue().equals(filterField.getValue())) {
308 //TODO: check v4 v6 incompatibility
314 * Merge the current Match fields with the fields of the filter Match
315 * A check is first run to see if this Match is compatible with the
316 * filter Match. If it is not, the merge is not attempted.
322 public Match mergeWithFilter(Match filter) {
323 if (!this.conflictWithFilter(filter)) {
325 * No conflict with the filter
326 * We can copy over the fields which this match does not have
328 for (MatchType type : filter.getMatchesList()) {
329 if (this.isAny(type)) {
330 this.setField(filter.getField(type).clone());
338 public int hashCode() {
339 final int prime = 31;
341 result = prime * result + ((fields == null) ? 0 : fields.hashCode());
342 result = prime * result + matches;
347 public boolean equals(Object obj) {
352 if (getClass() != obj.getClass())
354 Match other = (Match) obj;
355 if (fields == null) {
356 if (other.fields != null)
358 } else if (!fields.equals(other.fields))
360 if (matches != other.matches)
366 public String toString() {
367 return "Match[" + fields.values() + "]";