blob: 7fefe405dce4349c1d6fd1582ef76f14d317ad65 [file] [log] [blame]
Kalhee Kim6222dbe2017-10-26 15:44:37 +00001/*
2 * Copyright 2017-present Open Networking Foundation
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.slf4j.Logger;
19
20import java.nio.ByteBuffer;
21import java.util.ArrayList;
22import java.util.Arrays;
23import java.util.List;
24import java.util.Objects;
25
26import static com.google.common.base.MoreObjects.toStringHelper;
27import static org.onlab.packet.PacketUtils.checkInput;
28import static org.slf4j.LoggerFactory.getLogger;
29
30/**
31 * Implements RIP Packet format, according to RFC 2453.
32 */
33
34public class RIP extends BasePacket {
35 /**
36 * Routing Information Protocol packet.
37 * ------------------------------------------ |cmdType (1) | version(1) |
38 * ------------------------------------------ |reserved (2) |
39 * ------------------------------------------ | route entries (n*20) |
40 * ------------------------------------------
41 *
42 */
43 // the case of no RIP entry
44 public static final int MIN_HEADER_LENGTH = 4;
45
46
47 private final Logger log = getLogger(getClass());
48
49 public enum CmdType {
50 RIPREQUEST(1),
51 RIPRESPONSE(2);
52
53 protected int value;
54
55 CmdType(final int value) {
56 this.value = value;
57 }
58
59 public int getValue() {
60 return this.value;
61 }
62
63 public static CmdType getType(final int value) {
64 switch (value) {
65 case 1:
66 return RIPREQUEST;
67 case 2:
68 return RIPRESPONSE;
69 default:
70 return null;
71 }
72 }
73 }
74
75 protected byte cmdType;
76 protected byte version;
77 protected short reserved;
78 protected List<RIPV2Entry> rtEntries = new ArrayList<RIPV2Entry>();
79 protected RIPV2AuthEntry authEntry = null;
80 protected byte[] rawData = null;
81
82 /**
83 * @return the cmdType
84 */
85 public byte getCmdType() {
86 return this.cmdType;
87 }
88
89 /**
90 * @param cmdType
91 * the cmdType to set
92 * @return this
93 */
94 public RIP setCmdType(final byte cmdType) {
95 this.cmdType = cmdType;
96 return this;
97 }
98
99 /**
100 * @return the version
101 */
102 public byte getVersion() {
103 return this.version;
104 }
105
106 /**
107 * @param version
108 * the version to set
109 * @return this
110 */
111 public RIP setVersion(final byte version) {
112 this.version = version;
113 return this;
114 }
115
116 /**
117 * @return the reserved short
118 */
119 public short getReserved() {
120 return this.reserved;
121 }
122
123 /**
124 * @param reserved
125 * the reserved short to set
126 * @return this
127 */
128 public RIP setReserved(final short reserved) {
129 this.reserved = reserved;
130 return this;
131 }
132
133 /**
134 * @return the route entries
135 */
136 public List<RIPV2Entry> getRtEntries() {
137 return this.rtEntries;
138 }
139
140 /**
141 * @param entries
142 * the route entries to set
143 * @return this
144 */
145 public RIP setRtEntries(final List<RIPV2Entry> entries) {
146 this.rtEntries = entries;
147 return this;
148 }
149 /**
150 * @return the authentication entry
151 */
152 public RIPV2AuthEntry getAuthEntry() {
153 return this.authEntry;
154 }
155
156 /**
157 * @return the raw data of whole RIP packet (after RIP header)
158 */
159 public byte[] getRawData() {
160 return this.rawData;
161 }
162
163 @Override
164 public byte[] serialize() {
165 // not guaranteed to retain length/exact format
166 this.resetChecksum();
167 int dataLength = MIN_HEADER_LENGTH + RIPV2Entry.ENTRY_LEN * rtEntries.size();
168 if (authEntry != null) {
169 dataLength += RIPV2Entry.ENTRY_LEN;
170 }
171 final byte[] data = new byte[dataLength];
172 final ByteBuffer bb = ByteBuffer.wrap(data);
173 bb.put(this.cmdType);
174 bb.put(this.version);
175 bb.putShort(this.reserved);
176 if (authEntry != null) {
177 bb.put(authEntry.serialize());
178 }
179 for (final RIPV2Entry entry : this.rtEntries) {
180 bb.put(entry.serialize());
181 }
182 // assume the rest is padded out with zeroes
183 return data;
184 }
185
186 /**
187 * Deserializer function for RIP packets.
188 *
189 * @return deserializer function
190 */
191 public static Deserializer<RIP> deserializer() {
192 return (data, offset, length) -> {
193 RIP rip = new RIP();
194
195 checkInput(data, offset, length, MIN_HEADER_LENGTH);
196
197 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
198 rip.rawData = Arrays.copyOfRange(data, offset, offset + length);
199
200
201 rip.cmdType = bb.get();
202 rip.version = bb.get();
203 rip.reserved = bb.getShort();
204
205 // read route entries
206 while (bb.hasRemaining() && (bb.remaining() >= RIPV2Entry.ENTRY_LEN)) {
207 byte[] rtData = new byte[RIPV2Entry.ENTRY_LEN];
208 bb.get(rtData);
209
210 if (rtData[0] == -1 && rtData[1] == -1) {
211 // second time reaching here is the signature at the end of the packet, don't process it
212 if (rip.authEntry == null) {
213 rip.authEntry = RIPV2AuthEntry.deserializer().deserialize(rtData, 0, rtData.length);
214 }
215 } else {
216 RIPV2Entry rtEntry = RIPV2Entry.deserializer().deserialize(rtData, 0, rtData.length);
217 rip.rtEntries.add(rtEntry);
218 }
219 }
220
221 return rip;
222 };
223 }
224 /*
225 * (non-Javadoc)
226 *
227 * @see java.lang.Object#hashCode()
228 */
229 @Override
230 public int hashCode() {
231 return Objects.hash(super.hashCode(), cmdType, reserved, version, authEntry, rtEntries);
232 }
233
234 /*
235 * (non-Javadoc)
236 *
237 * @see java.lang.Object#equals(java.lang.Object)
238 */
239 @Override
240 public boolean equals(final Object obj) {
241 if (this == obj) {
242 return true;
243 }
244 if (!(obj instanceof RIP)) {
245 return false;
246 }
247 final RIP that = (RIP) obj;
248
249
250 return super.equals(that) &&
251 Objects.equals(version, that.version) &&
252 Objects.equals(reserved, that.reserved) &&
253 Objects.equals(cmdType, that.cmdType) &&
254 Objects.equals(authEntry, that.authEntry) &&
255 Objects.equals(rtEntries, that.rtEntries);
256 }
257
258 @Override
259 public String toString() {
260 return toStringHelper(getClass())
261 .add("cmdType", Byte.toString(cmdType))
262 .add("version", Byte.toString(version))
263 .add("reserved", Short.toString(reserved))
264 .toString();
265 // TODO: need to handle route entries
266 }
267}