1c964267b130d8b9f82d5e3726cc446683dbc4bd
[controller.git] / opendaylight / sal / api / src / main / java / org / opendaylight / controller / sal / match / MatchType.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.sal.match;
10
11 import java.net.Inet4Address;
12 import java.net.InetAddress;
13 import java.util.Arrays;
14
15 import org.opendaylight.controller.sal.core.NodeConnector;
16 import org.opendaylight.controller.sal.utils.HexEncode;
17 import org.opendaylight.controller.sal.utils.NetUtils;
18
19 /**
20  * Represents the binding between the id, the value and mask type and the range
21  * values of the elements type that can be matched on the network
22  * frame/packet/message
23  */
24 public enum MatchType {
25     IN_PORT("inPort", 1 << 0, NodeConnector.class, 1, 0),
26     DL_SRC("dlSrc", 1 << 1, Byte[].class, 0, 0xffffffffffffL),
27     DL_DST("dlDst", 1 << 2, Byte[].class, 0, 0xffffffffffffL),
28     DL_VLAN("dlVlan", 1 << 3, Short.class, 0, 0xfff), // 2 bytes
29     DL_VLAN_PR("dlVlanPriority", 1 << 4, Byte.class, 0, 0x7), // 3 bits
30     DL_OUTER_VLAN("dlOuterVlan", 1 << 5, Short.class, 1, 0xfff),
31     DL_OUTER_VLAN_PR("dlOuterVlanPriority", 1 << 6, Short.class, 0, 0x7),
32     DL_TYPE("dlType", 1 << 7, Short.class, 0, 0xffff), // 2 bytes
33     NW_TOS("nwTOS", 1 << 8, Byte.class, 0, 0x3f), // 6 bits (DSCP field)
34     NW_PROTO("nwProto", 1 << 9, Byte.class, 0, 0xff), // 1 byte
35     NW_SRC("nwSrc", 1 << 10, InetAddress.class, 0, 0),
36     NW_DST("nwDst", 1 << 11, InetAddress.class, 0, 0),
37     TP_SRC("tpSrc", 1 << 12, Short.class, 1, 0xffff), // 2 bytes
38     TP_DST("tpDst", 1 << 13, Short.class, 1, 0xffff); // 2 bytes
39
40     // Used to indicate that no VLAN ID is set.
41     public static final short DL_VLAN_NONE = (short) 0;
42
43     private String id;
44     private int index;
45     private Class<?> dataType;
46     private long minValue;
47     private long maxValue;
48
49     private MatchType(String id, int index, Class<?> dataType, long minValue, long maxValue) {
50         this.id = id;
51         this.index = index;
52         this.dataType = dataType;
53         this.minValue = minValue;
54         this.maxValue = maxValue;
55     }
56
57     public String id() {
58         return id;
59     }
60
61     public int getIndex() {
62         return index;
63     }
64
65     public Class<?> dataType() {
66         return dataType;
67     }
68
69     public String getRange() {
70         return "[0x" + Long.toHexString(minValue) + "-0x" + Long.toHexString(maxValue) + "]";
71     }
72
73     /**
74      * Perform the assignment type validation
75      *
76      * @param value
77      * @param mask
78      * @return
79      */
80     public boolean isCongruentType(Object value, Object mask) {
81         // Mask type has to match value type
82         if (mask != null && (mask.getClass() != value.getClass())) {
83             return false;
84         }
85
86         Class<?> e = this.dataType();
87         Class<?> g = value.getClass();
88
89         // This is all what we need, if value type is same of match required
90         // type
91         if (g.equals(e)) {
92             return true;
93         }
94
95         // This is for the numeric class vs primitive congruence
96         // For what concerns here, for instance, Integer is congruent to int
97         if (e == Short.class) {
98             return g.equals(short.class);
99         }
100
101         if (e == Integer.class) {
102             return g.equals(int.class);
103         }
104
105         if (e == Byte.class) {
106             return g.equals(byte.class);
107         }
108
109         if (e == Byte[].class) {
110             return g.equals(byte[].class);
111         }
112
113         if (e == InetAddress.class) {
114             return g.getSuperclass().equals(InetAddress.class);
115         }
116         return false;
117     }
118
119     /**
120      * Perform the value and mask range validation
121      *
122      * @param value
123      * @param mask
124      * @return
125      */
126     public boolean isValid(Object value, Object mask) {
127         // Skip if main error
128         if (mask != null && (mask.getClass() != value.getClass())) {
129             return false;
130         }
131         // For the complex below types let's skip the value range check for now
132         if (this.dataType == InetAddress.class) {
133             return true;
134         }
135         if (this.dataType() == Byte[].class) {
136             return true;
137         }
138         if (this.dataType() == NodeConnector.class) {
139             return true;
140         }
141
142         int val = 0;
143         int msk = 0;
144         if (value.getClass() == Integer.class || value.getClass() == int.class) {
145             val = ((Integer) value).intValue();
146             msk = (mask != null) ? ((Integer) mask).intValue() : 0;
147
148         } else if (value.getClass() == Short.class || value.getClass() == short.class) {
149             val = ((Short) value).intValue() & 0xffff;
150             msk = (mask != null) ? ((Short) mask).intValue() & 0xffff : 0;
151
152         } else if (value.getClass() == Byte.class || value.getClass() == byte.class) {
153             val = ((Byte) value).intValue() & 0xff;
154             msk = (mask != null) ? ((Byte) mask).intValue() & 0xff : 0;
155         }
156         return ((val >= minValue && val <= maxValue) && (mask == null || (msk >= minValue && msk <= maxValue)));
157
158     }
159
160     /**
161      * Return the mask value in 64 bits bitmask form
162      *
163      * @param mask
164      * @return
165      */
166     public long getBitMask(Object mask) {
167         if (this.dataType == InetAddress.class) {
168             // TODO handle Inet v4 and v6 v6 will have a second upper mask
169             return 0;
170         }
171         if (this.dataType() == Byte[].class) {
172             if (mask == null) {
173                 return 0xffffffffffffL;
174             }
175             byte mac[] = (byte[]) mask;
176             long bitmask = 0;
177             for (short i = 0; i < 6; i++) {
178                 bitmask |= ((mac[i] & 0xffL) << ((5 - i) * 8));
179             }
180             return bitmask;
181         }
182         if (this.dataType == Integer.class || this.dataType == int.class) {
183             return (mask == null) ? this.maxValue : ((Integer) mask).longValue();
184
185         }
186         if (this.dataType == Short.class || this.dataType == short.class) {
187             return (mask == null) ? this.maxValue : ((Short) mask).longValue();
188         }
189         if (this.dataType == Byte.class || this.dataType == byte.class) {
190             return (mask == null) ? this.maxValue : ((Byte) mask).longValue();
191
192         }
193         return 0L;
194     }
195
196     public String stringify(Object value) {
197         if (value == null) {
198             return null;
199         }
200
201         switch (this) {
202         case DL_DST:
203         case DL_SRC:
204             return HexEncode.bytesToHexStringFormat((byte[]) value);
205         case DL_TYPE:
206         case DL_VLAN:
207             return ((Integer) NetUtils.getUnsignedShort((Short) value)).toString();
208         case NW_SRC:
209         case NW_DST:
210             return ((InetAddress) value).getHostAddress();
211         case NW_TOS:
212             return ((Integer) NetUtils.getUnsignedByte((Byte) value)).toString();
213         case TP_SRC:
214         case TP_DST:
215             return ((Integer) NetUtils.getUnsignedShort((Short) value)).toString();
216         default:
217             break;
218         }
219         return value.toString();
220     }
221
222     public int valueHashCode(Object o) {
223         if (o == null) {
224             return 0;
225         }
226         switch (this) {
227         case DL_SRC:
228         case DL_DST:
229             return NetUtils.byteArray4ToInt((byte[])o);
230         default:
231             return o.hashCode();
232         }
233     }
234
235     public int hashCode(Object v, Object m) {
236         final int prime = 31;
237         int result = 1;
238         result = prime * result + this.hashCode();
239
240         switch (this) {
241         case DL_SRC:
242         case DL_DST:
243             result = prime * result + ((v == null)? 0 : NetUtils.byteArray4ToInt((byte[])v));
244             result = prime * result + ((m == null)? 0 : NetUtils.byteArray4ToInt((byte[])m));
245             break;
246         case NW_SRC:
247         case NW_DST:
248             // Hash code has to take into account only prefix address
249             InetAddress ip = (InetAddress) v;
250             int maskLen = (m == null) ? ((ip instanceof Inet4Address) ? 32 : 128) : NetUtils
251                     .getSubnetMaskLength((InetAddress) m);
252             InetAddress prefix = NetUtils.getSubnetPrefix(ip, maskLen);
253             result = prime * result + ((v == null)? 0 : prefix.hashCode());
254             break;
255         default:
256             result = prime * result + ((v == null)? 0 : v.hashCode());
257             result = prime * result + ((m == null)? 0 : m.hashCode());
258         }
259         return result;
260     }
261     public boolean equalValues(Object a, Object b) {
262         if (a == b) {
263             return true;
264         }
265         if (a == null || b == null) {
266             return false;
267         }
268         switch (this) {
269         case DL_DST:
270         case DL_SRC:
271             return Arrays.equals((byte[]) a, (byte[]) b);
272         default:
273             return a.equals(b);
274         }
275     }
276
277     public boolean equalMasks(Object a, Object b) {
278         if (a == b) {
279             return true;
280         }
281         switch (this) {
282         case NW_SRC:
283         case NW_DST:
284             /*
285              * For network address mask, network node may return full mask for
286              * flows the controller generated with a null mask object
287              */
288             if (a == null || b == null) {
289                 InetAddress mask = (a == null) ? (InetAddress) b : (InetAddress) a;
290                 int maxLength = (mask instanceof Inet4Address) ? 32 : 128;
291                 return (NetUtils.getSubnetMaskLength(mask) == maxLength);
292             }
293         default:
294             if (a == null) {
295                 return false;
296             }
297             return a.equals(b);
298         }
299     }
300
301     public boolean equals(Object value1, Object value2, Object mask1, Object mask2) {
302         switch (this) {
303         case NW_SRC:
304         case NW_DST:
305             // Equality to be checked against prefix addresses
306             InetAddress thisIP = (InetAddress) value1;
307             int thisMaskLen = (mask1 == null) ? ((thisIP instanceof Inet4Address) ? 32 : 128) : NetUtils
308                     .getSubnetMaskLength((InetAddress) mask1);
309             InetAddress otherIP = (InetAddress) value2;
310             int otherMaskLen = (mask2 == null) ? ((otherIP instanceof Inet4Address) ? 32 : 128) : NetUtils
311                     .getSubnetMaskLength((InetAddress) mask2);
312
313             return NetUtils.getSubnetPrefix(thisIP, thisMaskLen)
314                     .equals(NetUtils.getSubnetPrefix(otherIP, otherMaskLen));
315         default:
316             return (this.equalValues(value1, value2) && this.equalMasks(mask1, mask2));
317         }
318     }
319 }