blob: 37875109fef2b4d43068892c549674ae01e2bcd9 [file] [log] [blame]
Rusty Eddy80f12522015-09-03 22:42:02 +00001/*
2 * Copyright 2015 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 */
16package org.onlab.packet;
17
18import org.onlab.packet.pim.PIMHello;
19import org.onlab.packet.pim.PIMJoinPrune;
20
21import java.nio.ByteBuffer;
22import java.util.HashMap;
23import java.util.Map;
24
Jian Li5fc14292015-12-04 11:30:46 -080025import static com.google.common.base.MoreObjects.toStringHelper;
Rusty Eddy80f12522015-09-03 22:42:02 +000026import static org.onlab.packet.PacketUtils.checkInput;
27
28/**
29 * Implements PIM control packet format.
30 */
31public class PIM extends BasePacket {
32
33 public static final IpAddress PIM_ADDRESS = IpAddress.valueOf("224.0.0.13");
34
35 public static final byte TYPE_HELLO = 0x00;
36 public static final byte TYPE_REGISTER = 0x01;
Rusty Eddy9cbc0952015-09-14 22:29:07 +000037 public static final byte TYPE_REGISTER_STOP = 0x02;
Rusty Eddy80f12522015-09-03 22:42:02 +000038 public static final byte TYPE_JOIN_PRUNE_REQUEST = 0x03;
39 public static final byte TYPE_BOOTSTRAP = 0x04;
40 public static final byte TYPE_ASSERT = 0x05;
41 public static final byte TYPE_GRAFT = 0x06;
42 public static final byte TYPE_GRAFT_ACK = 0x07;
43 public static final byte TYPE_CANDIDATE_RP_ADV = 0x08;
44
45 public static final int PIM_HEADER_LEN = 4;
46
Rusty Eddy0c12e402015-10-19 19:27:01 -070047 public static final byte ADDRESS_FAMILY_IP4 = 0x1;
48 public static final byte ADDRESS_FAMILY_IP6 = 0x2;
49
Rusty Eddy80f12522015-09-03 22:42:02 +000050 public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP =
51 new HashMap<>();
52
53 static {
54 PIM.PROTOCOL_DESERIALIZER_MAP.put(PIM.TYPE_HELLO, PIMHello.deserializer());
55 PIM.PROTOCOL_DESERIALIZER_MAP.put(PIM.TYPE_JOIN_PRUNE_REQUEST, PIMJoinPrune.deserializer());
56 }
57
58 /*
59 * PIM Header fields
60 */
61 protected byte version;
62 protected byte type;
63 protected byte reserved;
64 protected short checksum;
65
66 /**
67 * Default constructor.
68 */
69 public PIM() {
70 super();
71 this.version = 2;
72 this.reserved = 0;
73 }
74
75 /**
76 * Return the PIM message type.
77 *
78 * @return the pimMsgType
79 */
80 public byte getPimMsgType() {
81 return this.type;
82 }
83
84 /**
85 * Set the PIM message type. Currently PIMJoinPrune and PIMHello are
86 * supported.
87 *
88 * @param type PIM message type
89 * @return PIM Header
90 */
91 public PIM setPIMType(final byte type) {
92 this.type = type;
93 return this;
94 }
95
96 /**
97 * Get the version of PIM.
98 *
99 * @return the PIM version. Must be 2.
100 */
101 public byte getVersion() {
102 return version;
103 }
104
105 /**
106 * Set the PIM version type. Should not change from 2.
107 *
Thomas Vachuskab9c7ea62015-09-10 15:17:02 -0700108 * @param version PIM version
Rusty Eddy80f12522015-09-03 22:42:02 +0000109 */
110 public void setVersion(byte version) {
111 this.version = version;
112 }
113
114 /**
115 * Get the reserved field.
116 *
117 * @return the reserved field. Must be ignored.
118 */
119 public byte getReserved() {
120 return reserved;
121 }
122
123 /**
124 * Set the reserved field.
125 *
126 * @param reserved should be 0
127 */
128 public void setReserved(byte reserved) {
129 this.reserved = reserved;
130 }
131
132 /**
133 * Get the checksum of this packet.
134 *
135 * @return the checksum
136 */
137 public short getChecksum() {
138 return checksum;
139 }
140
141 /**
142 * Set the checksum.
143 *
144 * @param checksum the checksum
145 */
146 public void setChecksum(short checksum) {
147 this.checksum = checksum;
148 }
149
150 /*
151 * (non-Javadoc)
152 *
153 * @see java.lang.Object#hashCode()
154 */
155 @Override
156 public int hashCode() {
157 final int prime = 5807;
158 int result = super.hashCode();
159 result = prime * result + this.type;
160 result = prime * result + this.version;
161 result = prime * result + this.checksum;
162 return result;
163 }
164
165 /*
166 * (non-Javadoc)
167 *
168 * @see java.lang.Object#equals(java.lang.Object)
169 */
170 @Override
171 public boolean equals(final Object obj) {
172 if (this == obj) {
173 return true;
174 }
175 if (!super.equals(obj)) {
176 return false;
177 }
178 if (!(obj instanceof PIM)) {
179 return false;
180 }
181 final PIM other = (PIM) obj;
182 if (this.type != other.type) {
183 return false;
184 }
185 if (this.version != other.version) {
186 return false;
187 }
188 if (this.checksum != other.checksum) {
189 return false;
190 }
191 return true;
192 }
193
194 /**
195 * Serializes the packet. Will compute and set the following fields if they
196 * are set to specific values at the time serialize is called: -checksum : 0
197 * -length : 0
198 *
199 * @return will return the serialized packet
200 */
201 @Override
202 public byte[] serialize() {
203 int length = 4;
204 byte[] payloadData = null;
205 if (this.payload != null) {
206 this.payload.setParent(this);
207 payloadData = this.payload.serialize();
208 length += payloadData.length;
209 }
210
211 final byte[] data = new byte[length];
212 final ByteBuffer bb = ByteBuffer.wrap(data);
213
214 bb.put((byte) ((this.version & 0xf) << 4 | this.type & 0xf));
215 bb.put(this.reserved);
216 bb.putShort(this.checksum);
217 if (payloadData != null) {
218 bb.put(payloadData);
219 }
220
221 if (this.parent != null && this.parent instanceof PIM) {
222 ((PIM) this.parent).setPIMType(TYPE_JOIN_PRUNE_REQUEST);
223 }
224
225 // compute checksum if needed
226 if (this.checksum == 0) {
227 bb.rewind();
228 int accumulation = 0;
229
230 for (int i = 0; i < length / 2; ++i) {
231 accumulation += 0xffff & bb.getShort();
232 }
233 // pad to an even number of shorts
234 if (length % 2 > 0) {
235 accumulation += (bb.get() & 0xff) << 8;
236 }
237
238 accumulation = (accumulation >> 16 & 0xffff)
239 + (accumulation & 0xffff);
240 this.checksum = (short) (~accumulation & 0xffff);
241 bb.putShort(2, this.checksum);
242 }
243 return data;
244 }
245
246 /**
247 * Deserialize the PIM packet.
248 *
249 * @param data bytes to deserialize.
250 * @param offset offset to start deserializing from
251 * @param length length of the data to deserialize
252 *
253 * @return the deserialized PIM packet.
254 */
255 @Override
256 public IPacket deserialize(final byte[] data, final int offset,
257 final int length) {
258 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
259 this.type = bb.get();
260 this.version = bb.get();
261 this.checksum = bb.getShort();
262
263 //this.payload = new Data();
264 this.payload = this.payload.deserialize(data, bb.position(), bb.limit() - bb.position());
265 this.payload.setParent(this);
266 return this;
267 }
268 /**
269 * Deserializer function for IPv4 packets.
270 *
271 * @return deserializer function
272 */
273 public static Deserializer<PIM> deserializer() {
274 return (data, offset, length) -> {
275 checkInput(data, offset, length, PIM_HEADER_LEN);
276
277 PIM pim = new PIM();
278
279 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
280
281 byte versionByte = bb.get();
282 pim.version = (byte) (versionByte >> 4 & 0xf);
283 pim.setPIMType((byte) (versionByte & 0xf));
284 pim.reserved = bb.get();
285 pim.checksum = bb.getShort();
286
287 Deserializer<? extends IPacket> deserializer;
288 if (PIM.PROTOCOL_DESERIALIZER_MAP.containsKey(pim.getPimMsgType())) {
289 deserializer = PIM.PROTOCOL_DESERIALIZER_MAP.get(pim.getPimMsgType());
290 } else {
291 deserializer = Data.deserializer();
292 }
293
294 pim.payload = deserializer.deserialize(data, bb.position(), bb.limit() - bb.position());
295 pim.payload.setParent(pim);
296
297 return pim;
298 };
299 }
Jian Li5fc14292015-12-04 11:30:46 -0800300
301 @Override
302 public String toString() {
303 return toStringHelper(getClass())
304 .add("version", Byte.toString(version))
305 .add("type", Byte.toString(type))
306 .add("reserved", Byte.toString(reserved))
307 .add("checksum", Short.toString(reserved))
308 .toString();
309 }
Rusty Eddy80f12522015-09-03 22:42:02 +0000310}