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.Collection;
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 {
43 private static final Map<MatchType, MatchType> reversableMatches;
45 Map<MatchType, MatchType> map = new HashMap<MatchType, MatchType>();
46 map.put(MatchType.DL_SRC, MatchType.DL_DST);
47 map.put(MatchType.DL_DST, MatchType.DL_SRC);
48 map.put(MatchType.NW_SRC, MatchType.NW_DST);
49 map.put(MatchType.NW_DST, MatchType.NW_SRC);
50 map.put(MatchType.TP_SRC, MatchType.TP_DST);
51 map.put(MatchType.TP_DST, MatchType.TP_SRC);
52 reversableMatches = Collections.unmodifiableMap(map);
54 private Map<MatchType, MatchField> fields;
55 private int matches; // concise way to tell which fields the match is set for (may remove if not needed)
58 fields = new HashMap<MatchType, MatchField>();
62 public Match(Match match) {
63 fields = new HashMap<MatchType, MatchField>(match.fields);
64 matches = match.matches;
68 * Generic setter for frame/packet/message's header fields against which to match
69 * Note: For MAC addresses, please pass the cloned value to this function
71 * @param type packet's header field type
72 * @param value field's value to assign to the match
73 * @param mask field's bitmask to apply to the match (has to be of the same class type of value)
75 public void setField(MatchType type, Object value, Object mask) {
76 MatchField field = new MatchField(type, value, mask);
77 if (field.isValid()) {
78 fields.put(type, field);
79 matches |= type.getIndex();
84 * Generic setter for frame/packet/message's header fields against which to match
85 * Note: For MAC addresses, please pass the cloned value to this function
87 * @param type packet's header field type
88 * @param value field's value to assign to the match
90 public void setField(MatchType type, Object value) {
91 MatchField field = new MatchField(type, value);
92 if (field.isValid()) {
93 fields.put(type, field);
94 matches |= type.getIndex();
99 * Generic setter for frame/packet/message's header field against which to match
101 * @param field the fields parameters as MAtchField object
103 public void setField(MatchField field) {
104 if (field.isValid()) {
105 fields.put(field.getType(), field);
106 matches |= field.getType().getIndex();
111 * Generic method to clear a field from the match
113 public void clearField(MatchType type) {
115 matches &= ~type.getIndex();
119 * Generic getter for fields against which the match is programmed
121 * @param type frame/packet/message's header field type
124 public MatchField getField(MatchType type) {
125 return fields.get(type);
129 * Returns the fields the match is set for in a bitmask fashion
130 * Each bit represents a field the match is configured for
132 * @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 the list of MatchFields the match is set for
150 * @return List of individual MatchField values.
152 @XmlElement(name="matchField")
153 public List<MatchField> getMatchFields() {
154 return new ArrayList<MatchField>(fields.values());
158 * Returns whether this match is for an IPv6 flow
160 public boolean isIPv6() {
161 return (isPresent(MatchType.DL_TYPE)
162 && ((Short) getField(MatchType.DL_TYPE).getValue())
163 .equals(EtherTypes.IPv6.shortValue())
164 || isPresent(MatchType.NW_PROTO)
165 && ((Byte) getField(MatchType.NW_PROTO).getValue())
166 .equals(IPProtocols.IPV6ICMP.byteValue())
167 || isPresent(MatchType.NW_SRC)
168 && getField(MatchType.NW_SRC).getValue() instanceof Inet6Address || isPresent(MatchType.NW_DST)
169 && getField(MatchType.NW_DST).getValue() instanceof Inet6Address);
173 * Returns whether this match is for an IPv4 flow
175 public boolean isIPv4() {
180 * Returns whether for the specified field type the match is to be considered "any"
181 * Equivalent to say this match does not care about the value of the specified field
186 public boolean isAny(MatchType type) {
187 //return ((fields.get(type) == null) || (fields.get(type).getBitMask() == 0L));
188 return !fields.containsKey(type);
192 * Returns whether a match for the specified field type is configured
197 public boolean isPresent(MatchType type) {
198 return (fields.get(type) != null);
202 public Match clone() {
205 cloned = (Match) super.clone();
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
231 MatchType from = entry.getKey();
232 MatchType to = entry.getValue();
233 if (this.isPresent(from)) {
234 reverse.setField(to, this.getField(from).getValue(), this
235 .getField(from).getMask());
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) filter.getField(type)
297 InetAddress filterMask = (InetAddress) filter.getField(type)
299 // thisAddress has to be in same subnet of filterAddress
300 if (NetUtils.inetAddressConflict(thisAddress, filterAddress,
301 thisMask, filterMask)) {
306 if (!thisField.getValue().equals(filterField.getValue())) {
310 //TODO: check v4 v6 incompatibility
316 * Merge the current Match fields with the fields of the filter Match
317 * A check is first run to see if this Match is compatible with the
318 * filter Match. If it is not, the merge is not attempted.
324 public Match mergeWithFilter(Match filter) {
325 if (!this.conflictWithFilter(filter)) {
327 * No conflict with the filter
328 * We can copy over the fields which this match does not have
330 for (MatchType type : filter.getMatchesList()) {
331 if (this.isAny(type)) {
332 this.setField(filter.getField(type).clone());
340 public int hashCode() {
341 return HashCodeBuilder.reflectionHashCode(this);
345 public boolean equals(Object obj) {
346 return EqualsBuilder.reflectionEquals(this, obj);
350 public String toString() {
351 return "Match[" + fields.values() + "]";