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.matches = matches;
206 cloned.fields = new HashMap<MatchType, MatchField>();
207 for (Entry<MatchType, MatchField> entry : this.fields.entrySet()) {
208 cloned.fields.put(entry.getKey(), entry.getValue().clone());
210 } catch (CloneNotSupportedException e) {
211 throw new RuntimeException(e);
217 * Returns a reversed version of this match
218 * For example, in the reversed version the network source and destination
219 * addresses will be exchanged. Non symmetric match field will not be
220 * copied over into the reversed match version, like input port.
224 public Match reverse() {
225 // Copy over all fields
226 Match reverse = this.clone();
228 // Flip symmetric fields
229 for (Map.Entry<MatchType, MatchType> entry : Match.reversableMatches.entrySet()) {
230 MatchType from = entry.getKey();
231 MatchType to = entry.getValue();
232 if (this.isPresent(from)) {
233 reverse.setField(to, this.getField(from).getValue(), this.getField(from).getMask());
234 if (!this.isPresent(to)) {
235 reverse.clearField(from);
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
252 * In other words the function returns true if the set of packets described
253 * by one match and the set of packets described by the other match are
254 * disjoint. Equivalently, if the intersection of the two sets of packets
255 * described by the two matches is an empty.
257 * For example, Let's suppose the filter has the following MatchFields:
259 * NW_DST = 172.20.30.110/24
261 * while this match has the following MatchFields:
263 * NW_DST = 172.20.30.45/24
266 * Then the function would return false as the two Match are not
269 * Note: the mask value is taken into account only for MatchType.NW_SRC and
273 * the Match describing the filter
274 * @return true if the set of packets described by one match and the set of
275 * packets described by the other match are disjoint, false
278 public boolean conflictWithFilter(Match filter) {
279 return !this.intersetcs(filter);
283 * Merge the current Match fields with the fields of the filter Match. A
284 * check is first run to see if this Match is compatible with the filter
285 * Match. If it is not, the merge is not attempted.
287 * The result is the match object representing the intersection of the set
288 * of packets described by this match with the set of packets described by
289 * the filter match. If the intersection of the two sets is empty, the
290 * return match will be null.
293 * the match with which attempting the merge
294 * @return a new Match object describing the set of packets represented by
295 * the intersection of this and the filter matches. null if the
296 * intersection is empty.
298 public Match mergeWithFilter(Match filter) {
299 return this.getIntersection(filter);
303 * Return the match representing the intersection of the set of packets
304 * described by this match with the set of packets described by the other
305 * match. Such as m.getIntersection(m) == m, m.getIntersection(u) == m and
306 * m.getIntersection(o) == o where u is an empty match (universal set, all
307 * packets) and o is the null match (empty set).
310 * the match with which computing the intersection
311 * @return a new Match object representing the intersection of the set of
312 * packets described by this match with the set of packets described
313 * by the other match. null when the intersection is the empty set.
315 public Match getIntersection(Match other) {
316 // If no intersection, return the empty set
317 if (!this.intersetcs(other)) {
320 // Check if any of the two is the universal match
321 if (this.getMatches() == 0) {
322 return other.clone();
324 if (other.getMatches() == 0) {
327 // Derive the intersection
328 Match intersection = new Match();
329 for (MatchType type : MatchType.values()) {
330 if (this.isAny(type) && other.isAny(type)) {
333 if (this.isAny(type)) {
334 intersection.setField(other.getField(type).clone());
336 } else if (other.isAny(type)) {
337 intersection.setField(this.getField(type).clone());
340 // Either they are equal or it is about IP address
342 // When it is about IP address, take the wider prefix address
346 MatchField thisField = this.getField(type);
347 MatchField otherField = other.getField(type);
348 InetAddress thisAddress = (InetAddress) thisField.getValue();
349 InetAddress otherAddress = (InetAddress) otherField.getValue();
350 InetAddress thisMask = (InetAddress) thisField.getMask();
351 InetAddress otherMask = (InetAddress) otherField.getMask();
353 int thisMaskLen = (thisMask == null) ? ((thisAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
354 .getSubnetMaskLength(thisMask);
355 int otherMaskLen = (otherMask == null) ? ((otherAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
356 .getSubnetMaskLength(otherMask);
357 if (thisMaskLen < otherMaskLen) {
358 intersection.setField(new MatchField(type, NetUtils.getSubnetPrefix(otherAddress, otherMaskLen),
361 intersection.setField(new MatchField(type, NetUtils.getSubnetPrefix(thisAddress, thisMaskLen),
366 // this and other match field are equal for this type, pick this
368 intersection.setField(this.getField(type).clone());
375 * Checks whether the intersection of the set of packets described by this
376 * match with the set of packets described by the other match is non empty
378 * For example, if this match is: DL_SRC = 00:cc:bb:aa:11:22
380 * and the other match is: DL_TYPE = 0x800 NW_SRC = 1.2.3.4
382 * then their respective matching packets set intersection is non empty:
383 * DL_SRC = 00:cc:bb:aa:11:22 DL_TYPE = 0x800 NW_SRC = 1.2.3.4
386 * the other match with which testing the intersection
387 * @return true if the intersection of the respective matching packets sets
390 public boolean intersetcs(Match other) {
391 // No intersection with the empty set
395 // Always intersection with the universal set
396 if (this.getMatches() == 0 || other.getMatches() == 0) {
399 // Iterate through the MatchType defined in the filter
400 for (MatchType type : MatchType.values()) {
401 if (this.isAny(type) || other.isAny(type)) {
405 MatchField thisField = this.getField(type);
406 MatchField otherField = other.getField(type);
411 if (!Arrays.equals((byte[]) thisField.getValue(), (byte[]) otherField.getValue())) {
417 InetAddress thisAddress = (InetAddress) thisField.getValue();
418 InetAddress otherAddress = (InetAddress) otherField.getValue();
420 if (thisAddress instanceof Inet4Address && otherAddress instanceof Inet6Address
421 || thisAddress instanceof Inet6Address && otherAddress instanceof Inet4Address) {
424 InetAddress thisMask = (InetAddress) thisField.getMask();
425 InetAddress otherMask = (InetAddress) otherField.getMask();
426 if (NetUtils.inetAddressConflict(thisAddress, otherAddress, thisMask, otherMask)
427 && NetUtils.inetAddressConflict(otherAddress, thisAddress, otherMask, thisMask)) {
432 if (!thisField.getValue().equals(otherField.getValue())) {
441 public int hashCode() {
442 final int prime = 31;
444 result = prime * result + ((fields == null) ? 0 : fields.hashCode());
445 result = prime * result + matches;
450 public boolean equals(Object obj) {
457 if (getClass() != obj.getClass()) {
460 Match other = (Match) obj;
461 if (fields == null) {
462 if (other.fields != null) {
465 } else if (!fields.equals(other.fields)) {
468 if (matches != other.matches) {
475 public String toString() {
476 return "Match[" + fields.values() + "]";