Fix IPv6 + subnet flow installation
[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, 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             // Hash code has to take into account only prefix address
246             InetAddress ip = (InetAddress) v;
247             int maskLen = (m == null) ? ((ip instanceof Inet4Address) ? 32 : 128) : NetUtils
248                     .getSubnetMaskLength((InetAddress) m);
249             InetAddress prefix = NetUtils.getSubnetPrefix(ip, maskLen);
250             result = prime * result + ((v == null)? 0 : prefix.hashCode());
251             break;
252         default:
253             result = prime * result + ((v == null)? 0 : v.hashCode());
254             result = prime * result + ((m == null)? 0 : m.hashCode());
255         }
256         return result;
257     }
258     public boolean equalValues(Object a, Object b) {
259         if (a == b) {
260             return true;
261         }
262         if (a == null || b == null) {
263             return false;
264         }
265         switch (this) {
266         case DL_DST:
267         case DL_SRC:
268             return Arrays.equals((byte[]) a, (byte[]) b);
269         default:
270             return a.equals(b);
271         }
272     }
273
274     public boolean equalMasks(Object a, Object b) {
275         if (a == b) {
276             return true;
277         }
278         switch (this) {
279         case NW_SRC:
280         case NW_DST:
281             /*
282              * For network address mask, network node may return full mask for
283              * flows the controller generated with a null mask object
284              */
285             if (a == null || b == null) {
286                 InetAddress mask = (a == null) ? (InetAddress) b : (InetAddress) a;
287                 int maxLength = (mask instanceof Inet4Address) ? 32 : 128;
288                 return (NetUtils.getSubnetMaskLength(mask) == maxLength);
289             }
290         default:
291             if (a == null) {
292                 return false;
293             }
294             return a.equals(b);
295         }
296     }
297
298     public boolean equals(Object value1, Object value2, Object mask1, Object mask2) {
299         switch (this) {
300         case NW_SRC:
301         case NW_DST:
302             // Equality to be checked against prefix addresses
303             InetAddress thisIP = (InetAddress) value1;
304             int thisMaskLen = (mask1 == null) ? ((thisIP instanceof Inet4Address) ? 32 : 128) : NetUtils
305                     .getSubnetMaskLength((InetAddress) mask1);
306             InetAddress otherIP = (InetAddress) value2;
307             int otherMaskLen = (mask2 == null) ? ((otherIP instanceof Inet4Address) ? 32 : 128) : NetUtils
308                     .getSubnetMaskLength((InetAddress) mask2);
309
310             return NetUtils.getSubnetPrefix(thisIP, thisMaskLen)
311                     .equals(NetUtils.getSubnetPrefix(otherIP, otherMaskLen));
312         default:
313             return (this.equalValues(value1, value2) && this.equalMasks(mask1, mask2));
314         }
315     }
316 }