blob: 414e7241706e10ffb65a1390dc3f9f3254141ec3 [file] [log] [blame]
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present 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
Jian Li5fc14292015-12-04 11:30:46 -080034import static com.google.common.base.MoreObjects.toStringHelper;
Jonathan Hart2a655752015-04-07 16:46:33 -070035import static org.onlab.packet.PacketUtils.checkInput;
36
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080037/**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080038 * Implements IPv6 packet format. (RFC 2460)
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080039 */
Charles M.C. Chan94f37372015-01-10 17:53:42 +080040public class IPv6 extends BasePacket implements IExtensionHeader {
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080041 public static final byte FIXED_HEADER_LENGTH = 40; // bytes
42
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080043 public static final byte PROTOCOL_TCP = 0x6;
44 public static final byte PROTOCOL_UDP = 0x11;
45 public static final byte PROTOCOL_ICMP6 = 0x3A;
Charles M.C. Chan94f37372015-01-10 17:53:42 +080046 public static final byte PROTOCOL_HOPOPT = 0x00;
47 public static final byte PROTOCOL_ROUTING = 0x2B;
48 public static final byte PROTOCOL_FRAG = 0x2C;
49 public static final byte PROTOCOL_ESP = 0x32;
50 public static final byte PROTOCOL_AH = 0x33;
51 public static final byte PROTOCOL_DSTOPT = 0x3C;
52
53
Jonathan Hart2a655752015-04-07 16:46:33 -070054 public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP =
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080055 new HashMap<>();
56
57 static {
Jonathan Hart2a655752015-04-07 16:46:33 -070058 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ICMP6, ICMP6.deserializer());
59 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_TCP, TCP.deserializer());
60 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_UDP, UDP.deserializer());
61 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_HOPOPT, HopByHopOptions.deserializer());
62 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ROUTING, Routing.deserializer());
63 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_FRAG, Fragment.deserializer());
64 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ESP, EncapSecurityPayload.deserializer());
65 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_AH, Authentication.deserializer());
66 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_DSTOPT, DestinationOptions.deserializer());
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080067 }
68
69 protected byte version;
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080070 protected byte trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080071 protected int flowLabel;
72 protected short payloadLength;
73 protected byte nextHeader;
74 protected byte hopLimit;
75 protected byte[] sourceAddress = new byte[Ip6Address.BYTE_LENGTH];
76 protected byte[] destinationAddress = new byte[Ip6Address.BYTE_LENGTH];
77
78 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080079 * Default constructor that sets the version to 6.
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080080 */
81 public IPv6() {
82 super();
83 this.version = 6;
84 }
85
86 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080087 * Gets IP version.
88 *
89 * @return the IP version
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080090 */
91 public byte getVersion() {
92 return this.version;
93 }
94
95 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080096 * Sets IP version.
97 *
98 * @param version the IP version to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080099 * @return this
100 */
101 public IPv6 setVersion(final byte version) {
102 this.version = version;
103 return this;
104 }
105
106 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800107 * Gets traffic class.
108 *
109 * @return the traffic class
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800110 */
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800111 public byte getTrafficClass() {
112 return this.trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800113 }
114
115 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800116 * Sets traffic class.
117 *
118 * @param trafficClass the traffic class to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800119 * @return this
120 */
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800121 public IPv6 setTrafficClass(final byte trafficClass) {
122 this.trafficClass = trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800123 return this;
124 }
125
126 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800127 * Gets flow label.
128 *
129 * @return the flow label
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800130 */
131 public int getFlowLabel() {
132 return this.flowLabel;
133 }
134
135 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800136 * Sets flow label.
137 *
138 * @param flowLabel the flow label to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800139 * @return this
140 */
141 public IPv6 setFlowLabel(final int flowLabel) {
142 this.flowLabel = flowLabel;
143 return this;
144 }
145
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800146 @Override
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800147 public byte getNextHeader() {
148 return this.nextHeader;
149 }
150
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800151 @Override
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800152 public IPv6 setNextHeader(final byte nextHeader) {
153 this.nextHeader = nextHeader;
154 return this;
155 }
156
157 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800158 * Gets hop limit.
159 *
160 * @return the hop limit
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800161 */
162 public byte getHopLimit() {
163 return this.hopLimit;
164 }
165
166 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800167 * Sets hop limit.
168 *
169 * @param hopLimit the hop limit to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800170 * @return this
171 */
172 public IPv6 setHopLimit(final byte hopLimit) {
173 this.hopLimit = hopLimit;
174 return this;
175 }
176
177 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800178 * Gets source address.
179 *
180 * @return the IPv6 source address
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800181 */
182 public byte[] getSourceAddress() {
183 return this.sourceAddress;
184 }
185
186 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800187 * Sets source address.
188 *
189 * @param sourceAddress the IPv6 source address to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800190 * @return this
191 */
192 public IPv6 setSourceAddress(final byte[] sourceAddress) {
193 this.sourceAddress = Arrays.copyOfRange(sourceAddress, 0, Ip6Address.BYTE_LENGTH);
194 return this;
195 }
196
197 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800198 * Gets destination address.
199 *
200 * @return the IPv6 destination address
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800201 */
202 public byte[] getDestinationAddress() {
203 return this.destinationAddress;
204 }
205
206 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800207 * Sets destination address.
208 *
209 * @param destinationAddress the IPv6 destination address to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800210 * @return this
211 */
212 public IPv6 setDestinationAddress(final byte[] destinationAddress) {
213 this.destinationAddress = Arrays.copyOfRange(destinationAddress, 0, Ip6Address.BYTE_LENGTH);
214 return this;
215 }
216
217 @Override
218 public byte[] serialize() {
219 byte[] payloadData = null;
220 if (this.payload != null) {
221 this.payload.setParent(this);
222 payloadData = this.payload.serialize();
223 }
224
Charles M.C. Chan5c0b4762015-01-10 18:38:37 +0800225 this.payloadLength = 0;
226 if (payloadData != null) {
227 this.payloadLength = (short) payloadData.length;
228 }
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800229
230 final byte[] data = new byte[FIXED_HEADER_LENGTH + payloadLength];
231 final ByteBuffer bb = ByteBuffer.wrap(data);
232
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800233 bb.putInt((this.version & 0xf) << 28 | (this.trafficClass & 0xff) << 20 | this.flowLabel & 0xfffff);
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800234 bb.putShort(this.payloadLength);
235 bb.put(this.nextHeader);
236 bb.put(this.hopLimit);
237 bb.put(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
238 bb.put(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
239
240 if (payloadData != null) {
241 bb.put(payloadData);
242 }
243
244 return data;
245 }
246
247 @Override
248 public IPacket deserialize(final byte[] data, final int offset,
249 final int length) {
250 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
251 int iscratch;
252
253 iscratch = bb.getInt();
254 this.version = (byte) (iscratch >> 28 & 0xf);
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800255 this.trafficClass = (byte) (iscratch >> 20 & 0xff);
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800256 this.flowLabel = iscratch & 0xfffff;
257 this.payloadLength = bb.getShort();
258 this.nextHeader = bb.get();
259 this.hopLimit = bb.get();
260 bb.get(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
261 bb.get(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
262
Jonathan Hart2a655752015-04-07 16:46:33 -0700263 Deserializer<? extends IPacket> deserializer;
264 if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
265 deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800266 } else {
Jonathan Hart2a655752015-04-07 16:46:33 -0700267 deserializer = Data.deserializer();
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800268 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700269 try {
270 this.payload = deserializer.deserialize(data, bb.position(),
271 bb.limit() - bb.position());
272 this.payload.setParent(this);
273 } catch (DeserializationException e) {
274 return this;
275 }
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800276
277 return this;
278 }
279
280 /*
281 * (non-Javadoc)
282 *
283 * @see java.lang.Object#hashCode()
284 */
285 @Override
286 public int hashCode() {
287 final int prime = 2521;
288 int result = super.hashCode();
289 ByteBuffer bb;
290 bb = ByteBuffer.wrap(this.destinationAddress);
291 for (int i = 0; i < 4; i++) {
292 result = prime * result + bb.getInt();
293 }
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800294 result = prime * result + this.trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800295 result = prime * result + this.flowLabel;
296 result = prime * result + this.hopLimit;
297 result = prime * result + this.nextHeader;
298 result = prime * result + this.payloadLength;
299 bb = ByteBuffer.wrap(this.sourceAddress);
300 for (int i = 0; i < 4; i++) {
301 result = prime * result + bb.getInt();
302 }
303 result = prime * result + this.version;
304 return result;
305 }
306
307 /*
308 * (non-Javadoc)
309 *
310 * @see java.lang.Object#equals(java.lang.Object)
311 */
312 @Override
313 public boolean equals(final Object obj) {
314 if (this == obj) {
315 return true;
316 }
317 if (!super.equals(obj)) {
318 return false;
319 }
320 if (!(obj instanceof IPv6)) {
321 return false;
322 }
323 final IPv6 other = (IPv6) obj;
324 if (!Arrays.equals(this.destinationAddress, other.destinationAddress)) {
325 return false;
326 }
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800327 if (this.trafficClass != other.trafficClass) {
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800328 return false;
329 }
330 if (this.flowLabel != other.flowLabel) {
331 return false;
332 }
333 if (this.hopLimit != other.hopLimit) {
334 return false;
335 }
336 if (this.nextHeader != other.nextHeader) {
337 return false;
338 }
339 if (this.payloadLength != other.payloadLength) {
340 return false;
341 }
342 if (!Arrays.equals(this.sourceAddress, other.sourceAddress)) {
343 return false;
344 }
345 return true;
346 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700347
348 /**
349 * Deserializer function for IPv6 packets.
350 *
351 * @return deserializer function
352 */
353 public static Deserializer<IPv6> deserializer() {
354 return (data, offset, length) -> {
355 checkInput(data, offset, length, FIXED_HEADER_LENGTH);
356
357 IPv6 ipv6 = new IPv6();
358
359 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
360
361 int iscratch = bb.getInt();
362
363 ipv6.version = (byte) (iscratch >> 28 & 0xf);
364 ipv6.trafficClass = (byte) (iscratch >> 20 & 0xff);
365 ipv6.flowLabel = iscratch & 0xfffff;
366 ipv6.payloadLength = bb.getShort();
367 ipv6.nextHeader = bb.get();
368 ipv6.hopLimit = bb.get();
369 bb.get(ipv6.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
370 bb.get(ipv6.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
371
372 Deserializer<? extends IPacket> deserializer;
373 if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(ipv6.nextHeader)) {
374 deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(ipv6.nextHeader);
375 } else {
376 deserializer = Data.deserializer();
377 }
378 ipv6.payload = deserializer.deserialize(data, bb.position(),
379 bb.limit() - bb.position());
380 ipv6.payload.setParent(ipv6);
381
382 return ipv6;
383 };
384 }
Jian Li5fc14292015-12-04 11:30:46 -0800385
386 @Override
387 public String toString() {
388 return toStringHelper(getClass())
389 .add("version", Byte.toString(version))
390 .add("trafficClass", Byte.toString(trafficClass))
391 .add("flowLabel", Integer.toString(flowLabel))
392 .add("payloadLength", Short.toString(payloadLength))
393 .add("nextHeader", Byte.toString(nextHeader))
394 .add("hopLimit", Byte.toString(hopLimit))
395 .add("sourceAddress", Arrays.toString(sourceAddress))
396 .add("destinationAddress", Arrays.toString(destinationAddress))
397 .toString();
398 }
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800399}