blob: 3bb35c539e67d37308eb02be4a5503e3a86b9309 [file] [log] [blame]
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +08001/*
Charles M.C. Chan94f37372015-01-10 17:53:42 +08002 * Copyright 2014-2015 Open Networking Laboratory
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18
19package org.onlab.packet;
20
Charles M.C. Chan94f37372015-01-10 17:53:42 +080021import org.onlab.packet.ipv6.Authentication;
22import org.onlab.packet.ipv6.DestinationOptions;
23import org.onlab.packet.ipv6.EncapSecurityPayload;
24import org.onlab.packet.ipv6.Fragment;
25import org.onlab.packet.ipv6.IExtensionHeader;
26import org.onlab.packet.ipv6.HopByHopOptions;
27import org.onlab.packet.ipv6.Routing;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080028import java.nio.ByteBuffer;
29import java.util.Arrays;
30import java.util.HashMap;
31import java.util.Map;
32
33/**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080034 * Implements IPv6 packet format. (RFC 2460)
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080035 */
Charles M.C. Chan94f37372015-01-10 17:53:42 +080036public class IPv6 extends BasePacket implements IExtensionHeader {
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080037 public static final byte FIXED_HEADER_LENGTH = 40; // bytes
38
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080039 public static final byte PROTOCOL_TCP = 0x6;
40 public static final byte PROTOCOL_UDP = 0x11;
41 public static final byte PROTOCOL_ICMP6 = 0x3A;
Charles M.C. Chan94f37372015-01-10 17:53:42 +080042 public static final byte PROTOCOL_HOPOPT = 0x00;
43 public static final byte PROTOCOL_ROUTING = 0x2B;
44 public static final byte PROTOCOL_FRAG = 0x2C;
45 public static final byte PROTOCOL_ESP = 0x32;
46 public static final byte PROTOCOL_AH = 0x33;
47 public static final byte PROTOCOL_DSTOPT = 0x3C;
48
49
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080050 public static final Map<Byte, Class<? extends IPacket>> PROTOCOL_CLASS_MAP =
51 new HashMap<>();
52
53 static {
54 IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_ICMP6, ICMP6.class);
55 IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_TCP, TCP.class);
56 IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_UDP, UDP.class);
Charles M.C. Chan94f37372015-01-10 17:53:42 +080057 IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_HOPOPT, HopByHopOptions.class);
58 IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_ROUTING, Routing.class);
59 IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_FRAG, Fragment.class);
60 IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_ESP, EncapSecurityPayload.class);
61 IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_AH, Authentication.class);
62 IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_DSTOPT, DestinationOptions.class);
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080063 }
64
65 protected byte version;
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080066 protected byte trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080067 protected int flowLabel;
68 protected short payloadLength;
69 protected byte nextHeader;
70 protected byte hopLimit;
71 protected byte[] sourceAddress = new byte[Ip6Address.BYTE_LENGTH];
72 protected byte[] destinationAddress = new byte[Ip6Address.BYTE_LENGTH];
73
74 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080075 * Default constructor that sets the version to 6.
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080076 */
77 public IPv6() {
78 super();
79 this.version = 6;
80 }
81
82 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080083 * Gets IP version.
84 *
85 * @return the IP version
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080086 */
87 public byte getVersion() {
88 return this.version;
89 }
90
91 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080092 * Sets IP version.
93 *
94 * @param version the IP version to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080095 * @return this
96 */
97 public IPv6 setVersion(final byte version) {
98 this.version = version;
99 return this;
100 }
101
102 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800103 * Gets traffic class.
104 *
105 * @return the traffic class
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800106 */
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800107 public byte getTrafficClass() {
108 return this.trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800109 }
110
111 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800112 * Sets traffic class.
113 *
114 * @param trafficClass the traffic class to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800115 * @return this
116 */
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800117 public IPv6 setTrafficClass(final byte trafficClass) {
118 this.trafficClass = trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800119 return this;
120 }
121
122 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800123 * Gets flow label.
124 *
125 * @return the flow label
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800126 */
127 public int getFlowLabel() {
128 return this.flowLabel;
129 }
130
131 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800132 * Sets flow label.
133 *
134 * @param flowLabel the flow label to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800135 * @return this
136 */
137 public IPv6 setFlowLabel(final int flowLabel) {
138 this.flowLabel = flowLabel;
139 return this;
140 }
141
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800142 @Override
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800143 public byte getNextHeader() {
144 return this.nextHeader;
145 }
146
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800147 @Override
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800148 public IPv6 setNextHeader(final byte nextHeader) {
149 this.nextHeader = nextHeader;
150 return this;
151 }
152
153 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800154 * Gets hop limit.
155 *
156 * @return the hop limit
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800157 */
158 public byte getHopLimit() {
159 return this.hopLimit;
160 }
161
162 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800163 * Sets hop limit.
164 *
165 * @param hopLimit the hop limit to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800166 * @return this
167 */
168 public IPv6 setHopLimit(final byte hopLimit) {
169 this.hopLimit = hopLimit;
170 return this;
171 }
172
173 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800174 * Gets source address.
175 *
176 * @return the IPv6 source address
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800177 */
178 public byte[] getSourceAddress() {
179 return this.sourceAddress;
180 }
181
182 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800183 * Sets source address.
184 *
185 * @param sourceAddress the IPv6 source address to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800186 * @return this
187 */
188 public IPv6 setSourceAddress(final byte[] sourceAddress) {
189 this.sourceAddress = Arrays.copyOfRange(sourceAddress, 0, Ip6Address.BYTE_LENGTH);
190 return this;
191 }
192
193 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800194 * Gets destination address.
195 *
196 * @return the IPv6 destination address
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800197 */
198 public byte[] getDestinationAddress() {
199 return this.destinationAddress;
200 }
201
202 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800203 * Sets destination address.
204 *
205 * @param destinationAddress the IPv6 destination address to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800206 * @return this
207 */
208 public IPv6 setDestinationAddress(final byte[] destinationAddress) {
209 this.destinationAddress = Arrays.copyOfRange(destinationAddress, 0, Ip6Address.BYTE_LENGTH);
210 return this;
211 }
212
213 @Override
214 public byte[] serialize() {
215 byte[] payloadData = null;
216 if (this.payload != null) {
217 this.payload.setParent(this);
218 payloadData = this.payload.serialize();
219 }
220
Charles M.C. Chan5c0b4762015-01-10 18:38:37 +0800221 this.payloadLength = 0;
222 if (payloadData != null) {
223 this.payloadLength = (short) payloadData.length;
224 }
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800225
226 final byte[] data = new byte[FIXED_HEADER_LENGTH + payloadLength];
227 final ByteBuffer bb = ByteBuffer.wrap(data);
228
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800229 bb.putInt((this.version & 0xf) << 28 | (this.trafficClass & 0xff) << 20 | this.flowLabel & 0xfffff);
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800230 bb.putShort(this.payloadLength);
231 bb.put(this.nextHeader);
232 bb.put(this.hopLimit);
233 bb.put(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
234 bb.put(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
235
236 if (payloadData != null) {
237 bb.put(payloadData);
238 }
239
240 return data;
241 }
242
243 @Override
244 public IPacket deserialize(final byte[] data, final int offset,
245 final int length) {
246 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
247 int iscratch;
248
249 iscratch = bb.getInt();
250 this.version = (byte) (iscratch >> 28 & 0xf);
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800251 this.trafficClass = (byte) (iscratch >> 20 & 0xff);
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800252 this.flowLabel = iscratch & 0xfffff;
253 this.payloadLength = bb.getShort();
254 this.nextHeader = bb.get();
255 this.hopLimit = bb.get();
256 bb.get(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
257 bb.get(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
258
259 IPacket payload;
260 if (IPv6.PROTOCOL_CLASS_MAP.containsKey(this.nextHeader)) {
261 final Class<? extends IPacket> clazz = IPv6.PROTOCOL_CLASS_MAP
262 .get(this.nextHeader);
263 try {
264 payload = clazz.newInstance();
265 } catch (final Exception e) {
266 throw new RuntimeException(
267 "Error parsing payload for IPv6 packet", e);
268 }
269 } else {
270 payload = new Data();
271 }
272 this.payload = payload.deserialize(data, bb.position(),
273 bb.limit() - bb.position());
274 this.payload.setParent(this);
275
276 return this;
277 }
278
279 /*
280 * (non-Javadoc)
281 *
282 * @see java.lang.Object#hashCode()
283 */
284 @Override
285 public int hashCode() {
286 final int prime = 2521;
287 int result = super.hashCode();
288 ByteBuffer bb;
289 bb = ByteBuffer.wrap(this.destinationAddress);
290 for (int i = 0; i < 4; i++) {
291 result = prime * result + bb.getInt();
292 }
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800293 result = prime * result + this.trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800294 result = prime * result + this.flowLabel;
295 result = prime * result + this.hopLimit;
296 result = prime * result + this.nextHeader;
297 result = prime * result + this.payloadLength;
298 bb = ByteBuffer.wrap(this.sourceAddress);
299 for (int i = 0; i < 4; i++) {
300 result = prime * result + bb.getInt();
301 }
302 result = prime * result + this.version;
303 return result;
304 }
305
306 /*
307 * (non-Javadoc)
308 *
309 * @see java.lang.Object#equals(java.lang.Object)
310 */
311 @Override
312 public boolean equals(final Object obj) {
313 if (this == obj) {
314 return true;
315 }
316 if (!super.equals(obj)) {
317 return false;
318 }
319 if (!(obj instanceof IPv6)) {
320 return false;
321 }
322 final IPv6 other = (IPv6) obj;
323 if (!Arrays.equals(this.destinationAddress, other.destinationAddress)) {
324 return false;
325 }
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800326 if (this.trafficClass != other.trafficClass) {
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800327 return false;
328 }
329 if (this.flowLabel != other.flowLabel) {
330 return false;
331 }
332 if (this.hopLimit != other.hopLimit) {
333 return false;
334 }
335 if (this.nextHeader != other.nextHeader) {
336 return false;
337 }
338 if (this.payloadLength != other.payloadLength) {
339 return false;
340 }
341 if (!Arrays.equals(this.sourceAddress, other.sourceAddress)) {
342 return false;
343 }
344 return true;
345 }
346}