blob: ed26268660dc54bc4c78db14663b29f744e27452 [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
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080017package org.onlab.packet;
18
Charles M.C. Chan94f37372015-01-10 17:53:42 +080019import org.onlab.packet.ipv6.Authentication;
20import org.onlab.packet.ipv6.DestinationOptions;
21import org.onlab.packet.ipv6.EncapSecurityPayload;
22import org.onlab.packet.ipv6.Fragment;
Charles M.C. Chan94f37372015-01-10 17:53:42 +080023import org.onlab.packet.ipv6.HopByHopOptions;
Jonathan Hart2a655752015-04-07 16:46:33 -070024import org.onlab.packet.ipv6.IExtensionHeader;
Charles M.C. Chan94f37372015-01-10 17:53:42 +080025import org.onlab.packet.ipv6.Routing;
Jonathan Hart2a655752015-04-07 16:46:33 -070026
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080027import java.nio.ByteBuffer;
28import java.util.Arrays;
29import java.util.HashMap;
30import java.util.Map;
31
Jian Li5fc14292015-12-04 11:30:46 -080032import static com.google.common.base.MoreObjects.toStringHelper;
Jonathan Hart2a655752015-04-07 16:46:33 -070033import static org.onlab.packet.PacketUtils.checkInput;
34
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080035/**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080036 * Implements IPv6 packet format. (RFC 2460)
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080037 */
Jian Li1270aea2016-09-15 13:32:24 +090038public class IPv6 extends IP implements IExtensionHeader {
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080039 public static final byte FIXED_HEADER_LENGTH = 40; // bytes
40
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080041 public static final byte PROTOCOL_TCP = 0x6;
42 public static final byte PROTOCOL_UDP = 0x11;
43 public static final byte PROTOCOL_ICMP6 = 0x3A;
Charles M.C. Chan94f37372015-01-10 17:53:42 +080044 public static final byte PROTOCOL_HOPOPT = 0x00;
45 public static final byte PROTOCOL_ROUTING = 0x2B;
46 public static final byte PROTOCOL_FRAG = 0x2C;
47 public static final byte PROTOCOL_ESP = 0x32;
48 public static final byte PROTOCOL_AH = 0x33;
49 public static final byte PROTOCOL_DSTOPT = 0x3C;
50
51
Jonathan Hart2a655752015-04-07 16:46:33 -070052 public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP =
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080053 new HashMap<>();
54
55 static {
Jonathan Hart2a655752015-04-07 16:46:33 -070056 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ICMP6, ICMP6.deserializer());
57 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_TCP, TCP.deserializer());
58 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_UDP, UDP.deserializer());
59 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_HOPOPT, HopByHopOptions.deserializer());
60 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ROUTING, Routing.deserializer());
61 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_FRAG, Fragment.deserializer());
62 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ESP, EncapSecurityPayload.deserializer());
63 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_AH, Authentication.deserializer());
64 IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_DSTOPT, DestinationOptions.deserializer());
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080065 }
66
67 protected byte version;
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080068 protected byte trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080069 protected int flowLabel;
70 protected short payloadLength;
71 protected byte nextHeader;
72 protected byte hopLimit;
73 protected byte[] sourceAddress = new byte[Ip6Address.BYTE_LENGTH];
74 protected byte[] destinationAddress = new byte[Ip6Address.BYTE_LENGTH];
75
76 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080077 * Default constructor that sets the version to 6.
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080078 */
79 public IPv6() {
80 super();
81 this.version = 6;
82 }
83
Jian Li1270aea2016-09-15 13:32:24 +090084 @Override
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080085 public byte getVersion() {
86 return this.version;
87 }
88
Jian Li1270aea2016-09-15 13:32:24 +090089 @Override
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080090 public IPv6 setVersion(final byte version) {
91 this.version = version;
92 return this;
93 }
94
95 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080096 * Gets traffic class.
97 *
98 * @return the traffic class
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080099 */
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800100 public byte getTrafficClass() {
101 return this.trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800102 }
103
104 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800105 * Sets traffic class.
106 *
107 * @param trafficClass the traffic class to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800108 * @return this
109 */
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800110 public IPv6 setTrafficClass(final byte trafficClass) {
111 this.trafficClass = trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800112 return this;
113 }
114
115 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800116 * Gets flow label.
117 *
118 * @return the flow label
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800119 */
120 public int getFlowLabel() {
121 return this.flowLabel;
122 }
123
124 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800125 * Sets flow label.
126 *
127 * @param flowLabel the flow label to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800128 * @return this
129 */
130 public IPv6 setFlowLabel(final int flowLabel) {
131 this.flowLabel = flowLabel;
132 return this;
133 }
134
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800135 @Override
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800136 public byte getNextHeader() {
137 return this.nextHeader;
138 }
139
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800140 @Override
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800141 public IPv6 setNextHeader(final byte nextHeader) {
142 this.nextHeader = nextHeader;
143 return this;
144 }
145
146 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800147 * Gets hop limit.
148 *
149 * @return the hop limit
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800150 */
151 public byte getHopLimit() {
152 return this.hopLimit;
153 }
154
155 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800156 * Sets hop limit.
157 *
158 * @param hopLimit the hop limit to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800159 * @return this
160 */
161 public IPv6 setHopLimit(final byte hopLimit) {
162 this.hopLimit = hopLimit;
163 return this;
164 }
165
166 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800167 * Gets source address.
168 *
169 * @return the IPv6 source address
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800170 */
171 public byte[] getSourceAddress() {
172 return this.sourceAddress;
173 }
174
175 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800176 * Sets source address.
177 *
178 * @param sourceAddress the IPv6 source address to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800179 * @return this
180 */
181 public IPv6 setSourceAddress(final byte[] sourceAddress) {
182 this.sourceAddress = Arrays.copyOfRange(sourceAddress, 0, Ip6Address.BYTE_LENGTH);
183 return this;
184 }
185
186 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800187 * Gets destination address.
188 *
189 * @return the IPv6 destination address
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800190 */
191 public byte[] getDestinationAddress() {
192 return this.destinationAddress;
193 }
194
195 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800196 * Sets destination address.
197 *
198 * @param destinationAddress the IPv6 destination address to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800199 * @return this
200 */
201 public IPv6 setDestinationAddress(final byte[] destinationAddress) {
202 this.destinationAddress = Arrays.copyOfRange(destinationAddress, 0, Ip6Address.BYTE_LENGTH);
203 return this;
204 }
205
206 @Override
207 public byte[] serialize() {
208 byte[] payloadData = null;
209 if (this.payload != null) {
210 this.payload.setParent(this);
211 payloadData = this.payload.serialize();
212 }
213
Charles M.C. Chan5c0b4762015-01-10 18:38:37 +0800214 this.payloadLength = 0;
215 if (payloadData != null) {
216 this.payloadLength = (short) payloadData.length;
217 }
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800218
219 final byte[] data = new byte[FIXED_HEADER_LENGTH + payloadLength];
220 final ByteBuffer bb = ByteBuffer.wrap(data);
221
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800222 bb.putInt((this.version & 0xf) << 28 | (this.trafficClass & 0xff) << 20 | this.flowLabel & 0xfffff);
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800223 bb.putShort(this.payloadLength);
224 bb.put(this.nextHeader);
225 bb.put(this.hopLimit);
226 bb.put(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
227 bb.put(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
228
229 if (payloadData != null) {
230 bb.put(payloadData);
231 }
232
233 return data;
234 }
235
236 @Override
237 public IPacket deserialize(final byte[] data, final int offset,
238 final int length) {
239 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
240 int iscratch;
241
242 iscratch = bb.getInt();
243 this.version = (byte) (iscratch >> 28 & 0xf);
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800244 this.trafficClass = (byte) (iscratch >> 20 & 0xff);
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800245 this.flowLabel = iscratch & 0xfffff;
246 this.payloadLength = bb.getShort();
247 this.nextHeader = bb.get();
248 this.hopLimit = bb.get();
249 bb.get(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
250 bb.get(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
251
Jonathan Hart2a655752015-04-07 16:46:33 -0700252 Deserializer<? extends IPacket> deserializer;
253 if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) {
254 deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader);
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800255 } else {
Jonathan Hart2a655752015-04-07 16:46:33 -0700256 deserializer = Data.deserializer();
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800257 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700258 try {
259 this.payload = deserializer.deserialize(data, bb.position(),
260 bb.limit() - bb.position());
261 this.payload.setParent(this);
262 } catch (DeserializationException e) {
263 return this;
264 }
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800265
266 return this;
267 }
268
269 /*
270 * (non-Javadoc)
271 *
272 * @see java.lang.Object#hashCode()
273 */
274 @Override
275 public int hashCode() {
276 final int prime = 2521;
277 int result = super.hashCode();
278 ByteBuffer bb;
279 bb = ByteBuffer.wrap(this.destinationAddress);
280 for (int i = 0; i < 4; i++) {
281 result = prime * result + bb.getInt();
282 }
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800283 result = prime * result + this.trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800284 result = prime * result + this.flowLabel;
285 result = prime * result + this.hopLimit;
286 result = prime * result + this.nextHeader;
287 result = prime * result + this.payloadLength;
288 bb = ByteBuffer.wrap(this.sourceAddress);
289 for (int i = 0; i < 4; i++) {
290 result = prime * result + bb.getInt();
291 }
292 result = prime * result + this.version;
293 return result;
294 }
295
296 /*
297 * (non-Javadoc)
298 *
299 * @see java.lang.Object#equals(java.lang.Object)
300 */
301 @Override
302 public boolean equals(final Object obj) {
303 if (this == obj) {
304 return true;
305 }
306 if (!super.equals(obj)) {
307 return false;
308 }
309 if (!(obj instanceof IPv6)) {
310 return false;
311 }
312 final IPv6 other = (IPv6) obj;
313 if (!Arrays.equals(this.destinationAddress, other.destinationAddress)) {
314 return false;
315 }
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800316 if (this.trafficClass != other.trafficClass) {
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800317 return false;
318 }
319 if (this.flowLabel != other.flowLabel) {
320 return false;
321 }
322 if (this.hopLimit != other.hopLimit) {
323 return false;
324 }
325 if (this.nextHeader != other.nextHeader) {
326 return false;
327 }
328 if (this.payloadLength != other.payloadLength) {
329 return false;
330 }
331 if (!Arrays.equals(this.sourceAddress, other.sourceAddress)) {
332 return false;
333 }
334 return true;
335 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700336
337 /**
338 * Deserializer function for IPv6 packets.
339 *
340 * @return deserializer function
341 */
342 public static Deserializer<IPv6> deserializer() {
343 return (data, offset, length) -> {
344 checkInput(data, offset, length, FIXED_HEADER_LENGTH);
345
346 IPv6 ipv6 = new IPv6();
347
348 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
349
350 int iscratch = bb.getInt();
351
352 ipv6.version = (byte) (iscratch >> 28 & 0xf);
353 ipv6.trafficClass = (byte) (iscratch >> 20 & 0xff);
354 ipv6.flowLabel = iscratch & 0xfffff;
355 ipv6.payloadLength = bb.getShort();
356 ipv6.nextHeader = bb.get();
357 ipv6.hopLimit = bb.get();
358 bb.get(ipv6.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
359 bb.get(ipv6.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
360
361 Deserializer<? extends IPacket> deserializer;
362 if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(ipv6.nextHeader)) {
363 deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(ipv6.nextHeader);
364 } else {
365 deserializer = Data.deserializer();
366 }
367 ipv6.payload = deserializer.deserialize(data, bb.position(),
368 bb.limit() - bb.position());
369 ipv6.payload.setParent(ipv6);
370
371 return ipv6;
372 };
373 }
Jian Li5fc14292015-12-04 11:30:46 -0800374
375 @Override
376 public String toString() {
377 return toStringHelper(getClass())
378 .add("version", Byte.toString(version))
379 .add("trafficClass", Byte.toString(trafficClass))
380 .add("flowLabel", Integer.toString(flowLabel))
381 .add("payloadLength", Short.toString(payloadLength))
382 .add("nextHeader", Byte.toString(nextHeader))
383 .add("hopLimit", Byte.toString(hopLimit))
384 .add("sourceAddress", Arrays.toString(sourceAddress))
385 .add("destinationAddress", Arrays.toString(destinationAddress))
386 .toString();
387 }
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800388}