2e87bd759b9eb7f4735282071cd99431236e2088
[openflowjava.git] / third-party / openflow-codec / src / main / java / org / openflow / codec / protocol / OFPMatch.java
1 package org.openflow.codec.protocol;
2
3 import java.io.Serializable;
4 import java.util.HashMap;
5 import java.util.Map;
6
7 import org.openflow.codec.io.IDataBuffer;
8
9 /**
10  * Represents an ofp_match structure
11  *
12  * @author AnilGujele
13  *
14  */
15 public class OFPMatch implements Cloneable, Serializable {
16     /**
17      * serialization id
18      */
19     private static final long serialVersionUID = 1L;
20     private static final short MINIMUM_LENGTH = 4;
21     /**
22      * Match size should be multiple of eight, so padding will be done based on
23      * length of match.
24      */
25     private static final int MULTIPLE_OF_EIGHT = 8;
26
27     private OFPMatchType matchType;
28     private short length;
29     private Map<String, OXMField> fieldMap;
30
31     /**
32      * constructor
33      */
34     public OFPMatch() {
35         matchType = OFPMatchType.OFPMT_OXM;
36         setLength(MINIMUM_LENGTH); // all match fields are wild card
37         fieldMap = new HashMap<String, OXMField>();
38     }
39
40     /**
41      * add match field
42      *
43      * @param matchField
44      */
45     public void addMatchField(OXMField matchField) {
46         fieldMap.put(matchField.getMatchField().name(), matchField);
47
48     }
49
50     /**
51      * remove match field
52      *
53      * @param matchField
54      */
55     public void removeMatchField(OXMField matchField) {
56         fieldMap.remove(matchField.getMatchField().name());
57     }
58
59     /**
60      * get the length OFPMatch TLV
61      *
62      * @return
63      */
64     public short getLength() {
65         length = OFPMatch.MINIMUM_LENGTH;
66         for (Map.Entry<String, OXMField> entry : fieldMap.entrySet()) {
67             length += entry.getValue().getLength();
68         }
69         return length;
70     }
71
72     /**
73      * get the length OFPMatch TLV
74      *
75      * @return
76      */
77     public short getLengthWithPadding() {
78         int matchLength = getLength();
79         int paddingLength = ((matchLength % MULTIPLE_OF_EIGHT) == 0) ? 0
80                 : (MULTIPLE_OF_EIGHT - (matchLength % MULTIPLE_OF_EIGHT));
81         length = (short) (matchLength + paddingLength);
82         return length;
83     }
84
85     /**
86      * set the length of OFPMatch TLV
87      *
88      * @param length
89      */
90     public void setLength(short length) {
91         this.length = length;
92     }
93
94     /**
95      * get the matchfield map
96      *
97      * @return
98      */
99     public Map<String, OXMField> getMatchFieldMap() {
100         return fieldMap;
101     }
102
103     /**
104      * set the matchfield map
105      *
106      * @param fieldMap
107      */
108     public void setMatchFieldMap(Map<String, OXMField> fieldMap) {
109         this.fieldMap = fieldMap;
110     }
111
112     /**
113      * Read this match from the specified DataBuffer
114      *
115      * @param data
116      *            - data to read to construct match object
117      * @return true - reading is successful , false - failed to read as data is
118      *         not proper or prerequisite is not matched
119      */
120     public boolean readFrom(IDataBuffer data) {
121         boolean result = false;
122         this.matchType = OFPMatchType.valueOf(data.getShort());
123         // check for valid match type
124         // if not match then either match type is deprecated or not supported
125         if (matchType == OFPMatchType.OFPMT_OXM) {
126             int length = data.getShort();
127             if (length >= MINIMUM_LENGTH) {
128                 // match size will be multiple of 8, so need to handle padding
129                 // if any
130                 int paddingLength = ((length % MULTIPLE_OF_EIGHT) == 0) ? 0
131                         : (MULTIPLE_OF_EIGHT - (length % MULTIPLE_OF_EIGHT));
132                 // length = length - MINIMUM_LENGTH - paddingLength;
133                 /* length of ofp_match, is excluding the padding */
134                 length = length - MINIMUM_LENGTH;
135                 // read match field
136                 while (length > 0) {
137                     OXMField oxmField = new OXMField();
138                     if (!oxmField.readFrom(data)) {
139                         // data is not valid, so log, move the data pointer and
140                         // return;
141                         byte[] junkData = new byte[length + paddingLength];
142                         data.get(junkData);
143                         return false;
144                     }
145
146                     length = length - oxmField.getLength();
147                     this.addMatchField(oxmField);
148                     this.length += oxmField.getLength();
149                     result = true;
150
151                 }
152                 // remove padding bytes
153                 byte[] pad = new byte[paddingLength];
154                 data.get(pad);
155                 // result = MatchUtil.hasPrerequisite(this);
156             }
157         }
158         return result;
159
160     }
161
162     /**
163      * Write this match binary format to the specified DataBuffer
164      *
165      * @param data
166      */
167     public void writeTo(IDataBuffer data) {
168         // TBD - we should proceed if prerequisite matching
169         // MatchUtil.hasPrerequisite(this);
170         data.putShort(matchType.getMatchTypeValue());
171         data.putShort(getLength());
172         for (Map.Entry<String, OXMField> entry : fieldMap.entrySet()) {
173             OXMField field = entry.getValue();
174             field.writeTo(data);
175         }
176         // match size should be multiple of 8, so need to handle padding if any
177         int paddingLength = ((getLength() % MULTIPLE_OF_EIGHT) == 0) ? 0
178                 : (MULTIPLE_OF_EIGHT - (getLength() % MULTIPLE_OF_EIGHT));
179         // add padding bytes
180         byte[] pad = new byte[paddingLength];
181         data.put(pad);
182
183     }
184
185     /**
186      * create the clone of this OFPMatch
187      *
188      */
189     @Override
190     public OFPMatch clone() {
191         try {
192             OFPMatch clonedOFMatch = (OFPMatch) super.clone();
193             clonedOFMatch.fieldMap = new HashMap<String, OXMField>();
194             for (Map.Entry<String, OXMField> entry : fieldMap.entrySet()) {
195                 clonedOFMatch.fieldMap.put(entry.getKey(), entry.getValue().clone());
196             }
197             return clonedOFMatch;
198         } catch (CloneNotSupportedException e) {
199             throw new RuntimeException(e);
200         }
201     }
202
203     /**
204      * to get the object hashcode
205      *
206      * @return
207      */
208     public int hashCode() {
209         final int prime = 722;
210         int result = prime + this.getLength();
211         result = prime * result + this.matchType.getMatchTypeValue();
212         result = prime * result + this.fieldMap.hashCode();
213         return result;
214     }
215
216     /**
217      * to check object equality
218      */
219     public boolean equals(Object obj) {
220         if (this == obj) {
221             return true;
222         }
223         if (null == obj) {
224             return false;
225         }
226         if (!(obj instanceof OFPMatch)) {
227             return false;
228         }
229         OFPMatch other = (OFPMatch) obj;
230         if (this.matchType != other.matchType) {
231             return false;
232         }
233         if (this.getLength() != other.getLength()) {
234             return false;
235         }
236
237         if (!this.fieldMap.equals(other.fieldMap)) {
238             return false;
239         }
240
241         return true;
242     }
243
244     /**
245      * String representation of Match object ex: OFPMatch[MatchType=OFPMT_OXM,
246      * Length=12, Match Fields[Type=OPENFLOW_BASIC-IPV4_SRC, Length=8, Value=[1,
247      * 2, 3, 4]]]
248      */
249     public String toString() {
250         StringBuffer buffer = new StringBuffer();
251         buffer.append("OFPMatch[");
252         buffer.append("MatchType=").append(matchType);
253         buffer.append(", Length=").append(getLength());
254         buffer.append(", Match Fields[");
255         int index = fieldMap.size();
256         for (Map.Entry<String, OXMField> entry : fieldMap.entrySet()) {
257             OXMField field = entry.getValue();
258             buffer.append(field.toString());
259             if (0 != --index) {
260                 buffer.append(",");
261             }
262         }
263         buffer.append("]]");
264         return buffer.toString();
265     }
266
267 }