blob: 2e59632adb1c2dde304baee82333629bbaf625df [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;
Charles M.C. Chan94f37372015-01-10 17:53:42 +080025import org.onlab.packet.ipv6.HopByHopOptions;
Jonathan Hart2a655752015-04-07 16:46:33 -070026import org.onlab.packet.ipv6.IExtensionHeader;
Charles M.C. Chan94f37372015-01-10 17:53:42 +080027import org.onlab.packet.ipv6.Routing;
Jonathan Hart2a655752015-04-07 16:46:33 -070028
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080029import java.nio.ByteBuffer;
30import java.util.Arrays;
31import java.util.HashMap;
32import java.util.Map;
33
Jonathan Hart2a655752015-04-07 16:46:33 -070034import static org.onlab.packet.PacketUtils.checkInput;
35
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080036/**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080037 * Implements IPv6 packet format. (RFC 2460)
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080038 */
Charles M.C. Chan94f37372015-01-10 17:53:42 +080039public class IPv6 extends BasePacket implements IExtensionHeader {
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080040 public static final byte FIXED_HEADER_LENGTH = 40; // bytes
41
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080042 public static final byte PROTOCOL_TCP = 0x6;
43 public static final byte PROTOCOL_UDP = 0x11;
44 public static final byte PROTOCOL_ICMP6 = 0x3A;
Charles M.C. Chan94f37372015-01-10 17:53:42 +080045 public static final byte PROTOCOL_HOPOPT = 0x00;
46 public static final byte PROTOCOL_ROUTING = 0x2B;
47 public static final byte PROTOCOL_FRAG = 0x2C;
48 public static final byte PROTOCOL_ESP = 0x32;
49 public static final byte PROTOCOL_AH = 0x33;
50 public static final byte PROTOCOL_DSTOPT = 0x3C;
51
52
Jonathan Hart2a655752015-04-07 16:46:33 -070053 public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP =
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080054 new HashMap<>();
55
56 static {
Jonathan Hart2a655752015-04-07 16:46:33 -070057 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ICMP6, ICMP6.deserializer());
58 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_TCP, TCP.deserializer());
59 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_UDP, UDP.deserializer());
60 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_HOPOPT, HopByHopOptions.deserializer());
61 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ROUTING, Routing.deserializer());
62 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_FRAG, Fragment.deserializer());
63 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ESP, EncapSecurityPayload.deserializer());
64 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_AH, Authentication.deserializer());
65 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_DSTOPT, DestinationOptions.deserializer());
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080066 }
67
68 protected byte version;
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080069 protected byte trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080070 protected int flowLabel;
71 protected short payloadLength;
72 protected byte nextHeader;
73 protected byte hopLimit;
74 protected byte[] sourceAddress = new byte[Ip6Address.BYTE_LENGTH];
75 protected byte[] destinationAddress = new byte[Ip6Address.BYTE_LENGTH];
76
77 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080078 * Default constructor that sets the version to 6.
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080079 */
80 public IPv6() {
81 super();
82 this.version = 6;
83 }
84
85 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080086 * Gets IP version.
87 *
88 * @return the IP version
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080089 */
90 public byte getVersion() {
91 return this.version;
92 }
93
94 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080095 * Sets IP version.
96 *
97 * @param version the IP version to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080098 * @return this
99 */
100 public IPv6 setVersion(final byte version) {
101 this.version = version;
102 return this;
103 }
104
105 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800106 * Gets traffic class.
107 *
108 * @return the traffic class
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800109 */
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800110 public byte getTrafficClass() {
111 return this.trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800112 }
113
114 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800115 * Sets traffic class.
116 *
117 * @param trafficClass the traffic class to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800118 * @return this
119 */
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800120 public IPv6 setTrafficClass(final byte trafficClass) {
121 this.trafficClass = trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800122 return this;
123 }
124
125 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800126 * Gets flow label.
127 *
128 * @return the flow label
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800129 */
130 public int getFlowLabel() {
131 return this.flowLabel;
132 }
133
134 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800135 * Sets flow label.
136 *
137 * @param flowLabel the flow label to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800138 * @return this
139 */
140 public IPv6 setFlowLabel(final int flowLabel) {
141 this.flowLabel = flowLabel;
142 return this;
143 }
144
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800145 @Override
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800146 public byte getNextHeader() {
147 return this.nextHeader;
148 }
149
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800150 @Override
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800151 public IPv6 setNextHeader(final byte nextHeader) {
152 this.nextHeader = nextHeader;
153 return this;
154 }
155
156 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800157 * Gets hop limit.
158 *
159 * @return the hop limit
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800160 */
161 public byte getHopLimit() {
162 return this.hopLimit;
163 }
164
165 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800166 * Sets hop limit.
167 *
168 * @param hopLimit the hop limit to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800169 * @return this
170 */
171 public IPv6 setHopLimit(final byte hopLimit) {
172 this.hopLimit = hopLimit;
173 return this;
174 }
175
176 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800177 * Gets source address.
178 *
179 * @return the IPv6 source address
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800180 */
181 public byte[] getSourceAddress() {
182 return this.sourceAddress;
183 }
184
185 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800186 * Sets source address.
187 *
188 * @param sourceAddress the IPv6 source address to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800189 * @return this
190 */
191 public IPv6 setSourceAddress(final byte[] sourceAddress) {
192 this.sourceAddress = Arrays.copyOfRange(sourceAddress, 0, Ip6Address.BYTE_LENGTH);
193 return this;
194 }
195
196 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800197 * Gets destination address.
198 *
199 * @return the IPv6 destination address
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800200 */
201 public byte[] getDestinationAddress() {
202 return this.destinationAddress;
203 }
204
205 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800206 * Sets destination address.
207 *
208 * @param destinationAddress the IPv6 destination address to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800209 * @return this
210 */
211 public IPv6 setDestinationAddress(final byte[] destinationAddress) {
212 this.destinationAddress = Arrays.copyOfRange(destinationAddress, 0, Ip6Address.BYTE_LENGTH);
213 return this;
214 }
215
216 @Override
217 public byte[] serialize() {
218 byte[] payloadData = null;
219 if (this.payload != null) {
220 this.payload.setParent(this);
221 payloadData = this.payload.serialize();
222 }
223
Charles M.C. Chan5c0b4762015-01-10 18:38:37 +0800224 this.payloadLength = 0;
225 if (payloadData != null) {
226 this.payloadLength = (short) payloadData.length;
227 }
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800228
229 final byte[] data = new byte[FIXED_HEADER_LENGTH + payloadLength];
230 final ByteBuffer bb = ByteBuffer.wrap(data);
231
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800232 bb.putInt((this.version & 0xf) << 28 | (this.trafficClass & 0xff) << 20 | this.flowLabel & 0xfffff);
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800233 bb.putShort(this.payloadLength);
234 bb.put(this.nextHeader);
235 bb.put(this.hopLimit);
236 bb.put(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
237 bb.put(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
238
239 if (payloadData != null) {
240 bb.put(payloadData);
241 }
242
243 return data;
244 }
245
246 @Override
247 public IPacket deserialize(final byte[] data, final int offset,
248 final int length) {
249 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
250 int iscratch;
251
252 iscratch = bb.getInt();
253 this.version = (byte) (iscratch >> 28 & 0xf);
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800254 this.trafficClass = (byte) (iscratch >> 20 & 0xff);
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800255 this.flowLabel = iscratch & 0xfffff;
256 this.payloadLength = bb.getShort();
257 this.nextHeader = bb.get();
258 this.hopLimit = bb.get();
259 bb.get(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
260 bb.get(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
261
Jonathan Hart2a655752015-04-07 16:46:33 -0700262 Deserializer<? extends IPacket> deserializer;
263 if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
264 deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800265 } else {
Jonathan Hart2a655752015-04-07 16:46:33 -0700266 deserializer = Data.deserializer();
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800267 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700268 try {
269 this.payload = deserializer.deserialize(data, bb.position(),
270 bb.limit() - bb.position());
271 this.payload.setParent(this);
272 } catch (DeserializationException e) {
273 return this;
274 }
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800275
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 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700346
347 /**
348 * Deserializer function for IPv6 packets.
349 *
350 * @return deserializer function
351 */
352 public static Deserializer<IPv6> deserializer() {
353 return (data, offset, length) -> {
354 checkInput(data, offset, length, FIXED_HEADER_LENGTH);
355
356 IPv6 ipv6 = new IPv6();
357
358 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
359
360 int iscratch = bb.getInt();
361
362 ipv6.version = (byte) (iscratch >> 28 & 0xf);
363 ipv6.trafficClass = (byte) (iscratch >> 20 & 0xff);
364 ipv6.flowLabel = iscratch & 0xfffff;
365 ipv6.payloadLength = bb.getShort();
366 ipv6.nextHeader = bb.get();
367 ipv6.hopLimit = bb.get();
368 bb.get(ipv6.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
369 bb.get(ipv6.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
370
371 Deserializer<? extends IPacket> deserializer;
372 if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(ipv6.nextHeader)) {
373 deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(ipv6.nextHeader);
374 } else {
375 deserializer = Data.deserializer();
376 }
377 ipv6.payload = deserializer.deserialize(data, bb.position(),
378 bb.limit() - bb.position());
379 ipv6.payload.setParent(ipv6);
380
381 return ipv6;
382 };
383 }
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800384}