Merge "Added StatusCode to Response.Status Mapping"
[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.Inet6Address;
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, 1, 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     private String id;
41     private int index;
42     private Class<?> dataType;
43     private long minValue;
44     private long maxValue;
45
46     private MatchType(String id, int index, Class<?> dataType, long minValue, long maxValue) {
47         this.id = id;
48         this.index = index;
49         this.dataType = dataType;
50         this.minValue = minValue;
51         this.maxValue = maxValue;
52     }
53
54     public String id() {
55         return id;
56     }
57
58     public int getIndex() {
59         return index;
60     }
61
62     public Class<?> dataType() {
63         return dataType;
64     }
65
66     public String getRange() {
67         return "[0x" + Long.toHexString(minValue) + "-0x" + Long.toHexString(maxValue) + "]";
68     }
69
70     /**
71      * Perform the assignment type validation
72      *
73      * @param value
74      * @param mask
75      * @return
76      */
77     public boolean isCongruentType(Object value, Object mask) {
78         // Mask type has to match value type
79         if (mask != null && (mask.getClass() != value.getClass())) {
80             return false;
81         }
82
83         Class<?> e = this.dataType();
84         Class<?> g = value.getClass();
85
86         // This is all what we need, if value type is same of match required
87         // type
88         if (g.equals(e)) {
89             return true;
90         }
91
92         // This is for the numeric class vs primitive congruence
93         // For what concerns here, for instance, Integer is congruent to int
94         if (e == Short.class) {
95             return g.equals(short.class);
96         }
97
98         if (e == Integer.class) {
99             return g.equals(int.class);
100         }
101
102         if (e == Byte.class) {
103             return g.equals(byte.class);
104         }
105
106         if (e == Byte[].class) {
107             return g.equals(byte[].class);
108         }
109
110         if (e == InetAddress.class) {
111             return g.getSuperclass().equals(InetAddress.class);
112         }
113         return false;
114     }
115
116     /**
117      * Perform the value and mask range validation
118      *
119      * @param value
120      * @param mask
121      * @return
122      */
123     public boolean isValid(Object value, Object mask) {
124         // Skip if main error
125         if (mask != null && (mask.getClass() != value.getClass())) {
126             return false;
127         }
128         // For the complex below types let's skip the value range check for now
129         if (this.dataType == InetAddress.class) {
130             return true;
131         }
132         if (this.dataType() == Byte[].class) {
133             return true;
134         }
135         if (this.dataType() == NodeConnector.class) {
136             return true;
137         }
138
139         int val = 0;
140         int msk = 0;
141         if (value.getClass() == Integer.class || value.getClass() == int.class) {
142             val = ((Integer) value).intValue();
143             msk = (mask != null) ? ((Integer) mask).intValue() : 0;
144
145         } else if (value.getClass() == Short.class || value.getClass() == short.class) {
146             val = ((Short) value).intValue() & 0xffff;
147             msk = (mask != null) ? ((Short) mask).intValue() & 0xffff : 0;
148
149         } else if (value.getClass() == Byte.class || value.getClass() == byte.class) {
150             val = ((Byte) value).intValue() & 0xff;
151             msk = (mask != null) ? ((Byte) mask).intValue() & 0xff : 0;
152         }
153         return ((val >= minValue && val <= maxValue) && (mask == null || (msk >= minValue && msk <= maxValue)));
154
155     }
156
157     /**
158      * Return the mask value in 64 bits bitmask form
159      *
160      * @param mask
161      * @return
162      */
163     public long getBitMask(Object mask) {
164         if (this.dataType == InetAddress.class) {
165             // TODO handle Inet v4 and v6 v6 will have a second upper mask
166             return 0;
167         }
168         if (this.dataType() == Byte[].class) {
169             if (mask == null) {
170                 return 0xffffffffffffL;
171             }
172             byte mac[] = (byte[]) mask;
173             long bitmask = 0;
174             for (short i = 0; i < 6; i++) {
175                 bitmask |= ((mac[i] & 0xffL) << ((5 - i) * 8));
176             }
177             return bitmask;
178         }
179         if (this.dataType == Integer.class || this.dataType == int.class) {
180             return (mask == null) ? this.maxValue : ((Integer) mask).longValue();
181
182         }
183         if (this.dataType == Short.class || this.dataType == short.class) {
184             return (mask == null) ? this.maxValue : ((Short) mask).longValue();
185         }
186         if (this.dataType == Byte.class || this.dataType == byte.class) {
187             return (mask == null) ? this.maxValue : ((Byte) mask).longValue();
188
189         }
190         return 0L;
191     }
192
193     public String stringify(Object value) {
194         if (value == null) {
195             return null;
196         }
197
198         switch (this) {
199         case DL_DST:
200         case DL_SRC:
201             return HexEncode.bytesToHexStringFormat((byte[]) value);
202         case DL_TYPE:
203         case DL_VLAN:
204             return ((Integer) NetUtils.getUnsignedShort((Short) value)).toString();
205         case NW_SRC:
206         case NW_DST:
207             return ((InetAddress) value).getHostAddress();
208         case NW_TOS:
209             return ((Integer) NetUtils.getUnsignedByte((Byte) value)).toString();
210         case TP_SRC:
211         case TP_DST:
212             return ((Integer) NetUtils.getUnsignedShort((Short) value)).toString();
213         default:
214             break;
215         }
216         return value.toString();
217     }
218
219     public int valueHashCode(Object o) {
220         if (o == null) {
221             return 0;
222         }
223         switch (this) {
224         case DL_SRC:
225         case DL_DST:
226             return NetUtils.byteArray4ToInt((byte[])o);
227         default:
228             return o.hashCode();
229         }
230     }
231
232     public int hashCode(Object v, Object m) {
233         final int prime = 31;
234         int result = 1;
235         result = prime * result + this.hashCode();
236
237         switch (this) {
238         case DL_SRC:
239         case DL_DST:
240             result = prime * result + ((v == null)? 0 : NetUtils.byteArray4ToInt((byte[])v));
241             result = prime * result + ((m == null)? 0 : NetUtils.byteArray4ToInt((byte[])m));
242             break;
243         case NW_SRC:
244         case NW_DST:
245             result = prime * result + ((v == null)? 0 : v.hashCode());
246             result = prime * result + ((m == null)? NetUtils.gethighestIP(v instanceof Inet6Address).hashCode() : m.hashCode());
247             break;
248         default:
249             result = prime * result + ((v == null)? 0 : v.hashCode());
250             result = prime * result + ((m == null)? 0 : m.hashCode());
251         }
252         return result;
253     }
254     public boolean equalValues(Object a, Object b) {
255         if (a == b) {
256             return true;
257         }
258         if (a == null || b == null) {
259             return false;
260         }
261         switch (this) {
262         case DL_DST:
263         case DL_SRC:
264             return Arrays.equals((byte[]) a, (byte[]) b);
265         default:
266             return a.equals(b);
267         }
268     }
269
270     public boolean equalMasks(Object a, Object b) {
271         if (a == b) {
272             return true;
273         }
274         switch (this) {
275         case NW_SRC:
276         case NW_DST:
277             /*
278              * For network address mask, network node may return full mask for
279              * flows the controller generated with a null mask object
280              */
281             byte maskBytes[] = null;
282             if (a == null) {
283                 maskBytes = ((InetAddress) b).getAddress();
284             } else if (b == null) {
285                 maskBytes = ((InetAddress) a).getAddress();
286             }
287             if (maskBytes != null) {
288                 return (NetUtils.getSubnetMaskLength(maskBytes) == 0);
289             }
290         default:
291             if (a == null) {
292                 return false;
293             }
294             return a.equals(b);
295         }
296     }
297 }