blob: 7f8a0d65f72cf07dca0dc9019eb5c39b40ffe23a [file] [log] [blame]
Charles M.C. Chan94f37372015-01-10 17:53:42 +08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Charles M.C. Chan94f37372015-01-10 17:53:42 +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
17package org.onlab.packet.ipv6;
18
19import org.onlab.packet.BasePacket;
20import org.onlab.packet.Data;
Jonathan Hart2a655752015-04-07 16:46:33 -070021import org.onlab.packet.Deserializer;
Charles M.C. Chan94f37372015-01-10 17:53:42 +080022import org.onlab.packet.IPacket;
23import org.onlab.packet.IPv6;
24
25import java.nio.ByteBuffer;
26import java.util.Arrays;
27
Jian Li5fc14292015-12-04 11:30:46 -080028import static com.google.common.base.MoreObjects.toStringHelper;
Jonathan Hart2a655752015-04-07 16:46:33 -070029import static org.onlab.packet.PacketUtils.checkHeaderLength;
30import static org.onlab.packet.PacketUtils.checkInput;
31
Charles M.C. Chan94f37372015-01-10 17:53:42 +080032/**
33 * Implements IPv6 routing extension header format. (RFC 2460)
34 */
35public class Routing extends BasePacket implements IExtensionHeader {
36 public static final byte FIXED_HEADER_LENGTH = 4; // bytes
37 public static final byte FIXED_ROUTING_DATA_LENGTH = 4; // bytes
38 public static final byte LENGTH_UNIT = 8; // bytes per unit
39
40 protected byte nextHeader;
41 protected byte headerExtLength;
42 protected byte routingType;
43 protected byte segmentsLeft;
44 protected byte[] routingData;
45
46 @Override
47 public byte getNextHeader() {
48 return this.nextHeader;
49 }
50
51 @Override
52 public Routing setNextHeader(final byte nextHeader) {
53 this.nextHeader = nextHeader;
54 return this;
55 }
56
57 /**
58 * Gets the extension length of this header.
59 *
60 * @return header length
61 */
62 public byte getHeaderExtLength() {
63 return this.headerExtLength;
64 }
65
66 /**
67 * Sets the extension length of this header.
68 *
69 * @param headerExtLength the header length to set
70 * @return this
71 */
72 public Routing setHeaderExtLength(final byte headerExtLength) {
73 this.headerExtLength = headerExtLength;
74 return this;
75 }
76
77 /**
78 * Gets the routing type of this header.
79 *
80 * @return routing type
81 */
82 public byte getRoutingType() {
83 return this.routingType;
84 }
85
86 /**
87 * Sets the routing type of this header.
88 *
89 * @param routingType the routing type to set
90 * @return this
91 */
92 public Routing setRoutingType(final byte routingType) {
93 this.routingType = routingType;
94 return this;
95 }
96
97 /**
98 * Gets the number of remaining route segments of this header.
99 *
100 * @return number of remaining route segments
101 */
102 public byte getSegmentsLeft() {
103 return this.segmentsLeft;
104 }
105
106 /**
107 * Sets the number of remaining route segments of this header.
108 *
109 * @param segmentsLeft the number of remaining route segments to set
110 * @return this
111 */
112 public Routing setSegmntsLeft(final byte segmentsLeft) {
113 this.segmentsLeft = segmentsLeft;
114 return this;
115 }
116
117 /**
118 * Gets the routing data.
119 *
120 * @return the routing data
121 */
122 public byte[] getRoutingData() {
123 return this.routingData;
124 }
125
126 /**
127 * Sets the routing data.
128 *
129 * @param routingData the routing data to set
130 * @return this
131 */
132 public Routing setRoutingData(final byte[] routingData) {
133 this.routingData =
134 Arrays.copyOfRange(routingData, 0, routingData.length);
135 return this;
136 }
137
138 @Override
139 public byte[] serialize() {
140 byte[] payloadData = null;
141 if (this.payload != null) {
142 this.payload.setParent(this);
143 payloadData = this.payload.serialize();
144 }
145
146 int headerLength = FIXED_HEADER_LENGTH + routingData.length;
147 int payloadLength = 0;
148 if (payloadData != null) {
149 payloadLength = payloadData.length;
150 }
151
152 final byte[] data = new byte[headerLength + payloadLength];
153 final ByteBuffer bb = ByteBuffer.wrap(data);
154
155 bb.put(this.nextHeader);
156 bb.put(this.headerExtLength);
157 bb.put(this.routingType);
158 bb.put(this.segmentsLeft);
159 bb.put(this.routingData, 0, routingData.length);
160
161 if (payloadData != null) {
162 bb.put(payloadData);
163 }
164
165 if (this.parent != null && this.parent instanceof IExtensionHeader) {
166 ((IExtensionHeader) this.parent).setNextHeader(IPv6.PROTOCOL_ROUTING);
167 }
168 return data;
169 }
170
Charles M.C. Chan94f37372015-01-10 17:53:42 +0800171 /*
172 * (non-Javadoc)
173 *
174 * @see java.lang.Object#hashCode()
175 */
176 @Override
177 public int hashCode() {
178 final int prime = 5807;
179 int result = super.hashCode();
180 result = prime * result + this.nextHeader;
181 result = prime * result + this.headerExtLength;
182 result = prime * result + this.routingType;
183 result = prime * result + this.segmentsLeft;
184 for (byte b : this.routingData) {
185 result = prime * result + b;
186 }
187 return result;
188 }
189
190 /*
191 * (non-Javadoc)
192 *
193 * @see java.lang.Object#equals(java.lang.Object)
194 */
195 @Override
196 public boolean equals(final Object obj) {
197 if (this == obj) {
198 return true;
199 }
200 if (!super.equals(obj)) {
201 return false;
202 }
203 if (!(obj instanceof Routing)) {
204 return false;
205 }
206 final Routing other = (Routing) obj;
207 if (this.nextHeader != other.nextHeader) {
208 return false;
209 }
210 if (this.headerExtLength != other.headerExtLength) {
211 return false;
212 }
213 if (this.routingType != other.routingType) {
214 return false;
215 }
216 if (this.segmentsLeft != other.segmentsLeft) {
217 return false;
218 }
219 if (!Arrays.equals(this.routingData, other.routingData)) {
220 return false;
221 }
222 return true;
223 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700224
225 /**
226 * Deserializer function for routing headers.
227 *
228 * @return deserializer function
229 */
230 public static Deserializer<Routing> deserializer() {
231 return (data, offset, length) -> {
232 checkInput(data, offset, length, FIXED_HEADER_LENGTH);
233
234 Routing routing = new Routing();
235
236 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
237 routing.nextHeader = bb.get();
238 routing.headerExtLength = bb.get();
239 routing.routingType = bb.get();
240 routing.segmentsLeft = bb.get();
241 int dataLength =
242 FIXED_ROUTING_DATA_LENGTH + LENGTH_UNIT * routing.headerExtLength;
243
244 checkHeaderLength(bb.remaining(), dataLength);
245
246 routing.routingData = new byte[dataLength];
247 bb.get(routing.routingData, 0, dataLength);
248
249 Deserializer<? extends IPacket> deserializer;
250 if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(routing.nextHeader)) {
251 deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(routing.nextHeader);
252 } else {
253 deserializer = new Data().deserializer();
254 }
255 routing.payload = deserializer.deserialize(data, bb.position(),
256 bb.limit() - bb.position());
257 routing.payload.setParent(routing);
258
259 return routing;
260 };
261 }
Jian Li5fc14292015-12-04 11:30:46 -0800262
263 @Override
264 public String toString() {
265 return toStringHelper(getClass())
266 .add("nextHeader", Byte.toString(nextHeader))
267 .add("headerExtLength", Byte.toString(headerExtLength))
268 .add("routingType", Byte.toString(routingType))
269 .add("segmentsLeft", Byte.toString(segmentsLeft))
270 .add("routingData", Arrays.toString(routingData))
271 .toString();
272 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700273}