blob: 53a1acee283d6425ca845bd4312ef6baba17766c [file] [log] [blame]
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +08001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
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
21import java.nio.ByteBuffer;
22import java.util.Arrays;
23import java.util.HashMap;
24import java.util.Map;
25
26/**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080027 * Implements IPv6 packet format. (RFC 2460)
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080028 */
29public class IPv6 extends BasePacket {
30 public static final byte FIXED_HEADER_LENGTH = 40; // bytes
31
32 // TODO: Implement extension header.
33 public static final byte PROTOCOL_TCP = 0x6;
34 public static final byte PROTOCOL_UDP = 0x11;
35 public static final byte PROTOCOL_ICMP6 = 0x3A;
36 public static final Map<Byte, Class<? extends IPacket>> PROTOCOL_CLASS_MAP =
37 new HashMap<>();
38
39 static {
40 IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_ICMP6, ICMP6.class);
41 IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_TCP, TCP.class);
42 IPv6.PROTOCOL_CLASS_MAP.put(IPv6.PROTOCOL_UDP, UDP.class);
43 }
44
45 protected byte version;
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080046 protected byte trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080047 protected int flowLabel;
48 protected short payloadLength;
49 protected byte nextHeader;
50 protected byte hopLimit;
51 protected byte[] sourceAddress = new byte[Ip6Address.BYTE_LENGTH];
52 protected byte[] destinationAddress = new byte[Ip6Address.BYTE_LENGTH];
53
54 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080055 * Default constructor that sets the version to 6.
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080056 */
57 public IPv6() {
58 super();
59 this.version = 6;
60 }
61
62 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080063 * Gets IP version.
64 *
65 * @return the IP version
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080066 */
67 public byte getVersion() {
68 return this.version;
69 }
70
71 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080072 * Sets IP version.
73 *
74 * @param version the IP version to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080075 * @return this
76 */
77 public IPv6 setVersion(final byte version) {
78 this.version = version;
79 return this;
80 }
81
82 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080083 * Gets traffic class.
84 *
85 * @return the traffic class
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080086 */
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080087 public byte getTrafficClass() {
88 return this.trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080089 }
90
91 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080092 * Sets traffic class.
93 *
94 * @param trafficClass the traffic class to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080095 * @return this
96 */
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +080097 public IPv6 setTrafficClass(final byte trafficClass) {
98 this.trafficClass = trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +080099 return this;
100 }
101
102 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800103 * Gets flow label.
104 *
105 * @return the flow label
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800106 */
107 public int getFlowLabel() {
108 return this.flowLabel;
109 }
110
111 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800112 * Sets flow label.
113 *
114 * @param flowLabel the flow label to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800115 * @return this
116 */
117 public IPv6 setFlowLabel(final int flowLabel) {
118 this.flowLabel = flowLabel;
119 return this;
120 }
121
122 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800123 * Gets next header.
124 *
125 * @return the next header
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800126 */
127 public byte getNextHeader() {
128 return this.nextHeader;
129 }
130
131 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800132 * Sets next header.
133 *
134 * @param nextHeader the next header to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800135 * @return this
136 */
137 public IPv6 setNextHeader(final byte nextHeader) {
138 this.nextHeader = nextHeader;
139 return this;
140 }
141
142 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800143 * Gets hop limit.
144 *
145 * @return the hop limit
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800146 */
147 public byte getHopLimit() {
148 return this.hopLimit;
149 }
150
151 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800152 * Sets hop limit.
153 *
154 * @param hopLimit the hop limit to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800155 * @return this
156 */
157 public IPv6 setHopLimit(final byte hopLimit) {
158 this.hopLimit = hopLimit;
159 return this;
160 }
161
162 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800163 * Gets source address.
164 *
165 * @return the IPv6 source address
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800166 */
167 public byte[] getSourceAddress() {
168 return this.sourceAddress;
169 }
170
171 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800172 * Sets source address.
173 *
174 * @param sourceAddress the IPv6 source address to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800175 * @return this
176 */
177 public IPv6 setSourceAddress(final byte[] sourceAddress) {
178 this.sourceAddress = Arrays.copyOfRange(sourceAddress, 0, Ip6Address.BYTE_LENGTH);
179 return this;
180 }
181
182 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800183 * Gets destination address.
184 *
185 * @return the IPv6 destination address
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800186 */
187 public byte[] getDestinationAddress() {
188 return this.destinationAddress;
189 }
190
191 /**
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800192 * Sets destination address.
193 *
194 * @param destinationAddress the IPv6 destination address to set
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800195 * @return this
196 */
197 public IPv6 setDestinationAddress(final byte[] destinationAddress) {
198 this.destinationAddress = Arrays.copyOfRange(destinationAddress, 0, Ip6Address.BYTE_LENGTH);
199 return this;
200 }
201
202 @Override
203 public byte[] serialize() {
204 byte[] payloadData = null;
205 if (this.payload != null) {
206 this.payload.setParent(this);
207 payloadData = this.payload.serialize();
208 }
209
210 this.payloadLength = payloadData == null ? 0 : (short) payloadData.length;
211
212 final byte[] data = new byte[FIXED_HEADER_LENGTH + payloadLength];
213 final ByteBuffer bb = ByteBuffer.wrap(data);
214
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800215 bb.putInt((this.version & 0xf) << 28 | (this.trafficClass & 0xff) << 20 | this.flowLabel & 0xfffff);
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800216 bb.putShort(this.payloadLength);
217 bb.put(this.nextHeader);
218 bb.put(this.hopLimit);
219 bb.put(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
220 bb.put(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
221
222 if (payloadData != null) {
223 bb.put(payloadData);
224 }
225
226 return data;
227 }
228
229 @Override
230 public IPacket deserialize(final byte[] data, final int offset,
231 final int length) {
232 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
233 int iscratch;
234
235 iscratch = bb.getInt();
236 this.version = (byte) (iscratch >> 28 & 0xf);
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800237 this.trafficClass = (byte) (iscratch >> 20 & 0xff);
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800238 this.flowLabel = iscratch & 0xfffff;
239 this.payloadLength = bb.getShort();
240 this.nextHeader = bb.get();
241 this.hopLimit = bb.get();
242 bb.get(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH);
243 bb.get(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH);
244
245 IPacket payload;
246 if (IPv6.PROTOCOL_CLASS_MAP.containsKey(this.nextHeader)) {
247 final Class<? extends IPacket> clazz = IPv6.PROTOCOL_CLASS_MAP
248 .get(this.nextHeader);
249 try {
250 payload = clazz.newInstance();
251 } catch (final Exception e) {
252 throw new RuntimeException(
253 "Error parsing payload for IPv6 packet", e);
254 }
255 } else {
256 payload = new Data();
257 }
258 this.payload = payload.deserialize(data, bb.position(),
259 bb.limit() - bb.position());
260 this.payload.setParent(this);
261
262 return this;
263 }
264
265 /*
266 * (non-Javadoc)
267 *
268 * @see java.lang.Object#hashCode()
269 */
270 @Override
271 public int hashCode() {
272 final int prime = 2521;
273 int result = super.hashCode();
274 ByteBuffer bb;
275 bb = ByteBuffer.wrap(this.destinationAddress);
276 for (int i = 0; i < 4; i++) {
277 result = prime * result + bb.getInt();
278 }
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800279 result = prime * result + this.trafficClass;
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800280 result = prime * result + this.flowLabel;
281 result = prime * result + this.hopLimit;
282 result = prime * result + this.nextHeader;
283 result = prime * result + this.payloadLength;
284 bb = ByteBuffer.wrap(this.sourceAddress);
285 for (int i = 0; i < 4; i++) {
286 result = prime * result + bb.getInt();
287 }
288 result = prime * result + this.version;
289 return result;
290 }
291
292 /*
293 * (non-Javadoc)
294 *
295 * @see java.lang.Object#equals(java.lang.Object)
296 */
297 @Override
298 public boolean equals(final Object obj) {
299 if (this == obj) {
300 return true;
301 }
302 if (!super.equals(obj)) {
303 return false;
304 }
305 if (!(obj instanceof IPv6)) {
306 return false;
307 }
308 final IPv6 other = (IPv6) obj;
309 if (!Arrays.equals(this.destinationAddress, other.destinationAddress)) {
310 return false;
311 }
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800312 if (this.trafficClass != other.trafficClass) {
Charles M.C. Chan93b7fb02014-12-28 03:59:36 +0800313 return false;
314 }
315 if (this.flowLabel != other.flowLabel) {
316 return false;
317 }
318 if (this.hopLimit != other.hopLimit) {
319 return false;
320 }
321 if (this.nextHeader != other.nextHeader) {
322 return false;
323 }
324 if (this.payloadLength != other.payloadLength) {
325 return false;
326 }
327 if (!Arrays.equals(this.sourceAddress, other.sourceAddress)) {
328 return false;
329 }
330 return true;
331 }
332}