blob: b6ed216d58ef529fd6ccc0207b40e0354069d173 [file] [log] [blame]
Jian Li451175e2016-07-19 23:22:20 +09001/*
2 * Copyright 2016-present 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.onosproject.lisp.msg.protocols;
17
Jian Li20850d32016-08-04 02:15:57 +090018import com.google.common.base.Objects;
Jian Lif59c0ad2016-08-02 18:11:30 +090019import com.google.common.collect.ImmutableList;
20import com.google.common.collect.Lists;
Jian Li451175e2016-07-19 23:22:20 +090021import io.netty.buffer.ByteBuf;
Jian Li47671902016-08-11 01:18:18 +090022import org.onlab.util.ByteOperator;
Jian Lif59c0ad2016-08-02 18:11:30 +090023import org.onlab.util.ImmutableByteSequence;
Jian Li26069e22016-08-10 22:00:52 +090024import org.onosproject.lisp.msg.exceptions.LispParseError;
Jian Lia7b394d2016-08-21 23:11:46 +090025import org.onosproject.lisp.msg.exceptions.LispReaderException;
Jian Liedc5db12016-08-23 17:30:19 +090026import org.onosproject.lisp.msg.exceptions.LispWriterException;
Jian Li451175e2016-07-19 23:22:20 +090027
Jian Liedc5db12016-08-23 17:30:19 +090028import java.util.Arrays;
Jian Li719b3bf2016-07-22 00:38:29 +090029import java.util.List;
30
Jian Li20850d32016-08-04 02:15:57 +090031import static com.google.common.base.MoreObjects.toStringHelper;
Jian Lie4ba2a42016-08-29 20:24:15 +090032import static org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.MapRecordReader;
33import static org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.MapRecordWriter;
Jian Li20850d32016-08-04 02:15:57 +090034
Jian Liedc5db12016-08-23 17:30:19 +090035
Jian Li451175e2016-07-19 23:22:20 +090036/**
37 * Default LISP map register message class.
38 */
Jian Lif59c0ad2016-08-02 18:11:30 +090039public final class DefaultLispMapRegister implements LispMapRegister {
40
41 private final long nonce;
42 private final short keyId;
Jian Liedc5db12016-08-23 17:30:19 +090043 private final short authDataLength;
Jian Lif59c0ad2016-08-02 18:11:30 +090044 private final byte[] authenticationData;
45 private final byte recordCount;
46 private final List<LispMapRecord> mapRecords;
47 private final boolean proxyMapReply;
48 private final boolean wantMapNotify;
49
50 /**
51 * A private constructor that protects object instantiation from external.
52 *
53 * @param nonce nonce
54 * @param keyId key identifier
55 * @param authenticationData authentication data
56 * @param recordCount record count number
57 * @param mapRecords a collection of map records
58 * @param proxyMapReply proxy map reply flag
59 * @param wantMapNotify want map notify flag
60 */
Jian Liedc5db12016-08-23 17:30:19 +090061 private DefaultLispMapRegister(long nonce, short keyId, short authDataLength,
Jian Lif59c0ad2016-08-02 18:11:30 +090062 byte[] authenticationData, byte recordCount,
63 List<LispMapRecord> mapRecords,
64 boolean proxyMapReply, boolean wantMapNotify) {
65 this.nonce = nonce;
66 this.keyId = keyId;
Jian Liedc5db12016-08-23 17:30:19 +090067 this.authDataLength = authDataLength;
Jian Lif59c0ad2016-08-02 18:11:30 +090068 this.authenticationData = authenticationData;
69 this.recordCount = recordCount;
70 this.mapRecords = mapRecords;
71 this.proxyMapReply = proxyMapReply;
72 this.wantMapNotify = wantMapNotify;
73 }
74
Jian Li451175e2016-07-19 23:22:20 +090075 @Override
76 public LispType getType() {
Jian Lif59c0ad2016-08-02 18:11:30 +090077 return LispType.LISP_MAP_REGISTER;
Jian Li451175e2016-07-19 23:22:20 +090078 }
79
80 @Override
81 public void writeTo(ByteBuf byteBuf) {
Jian Lif59c0ad2016-08-02 18:11:30 +090082 // TODO: serialize LispMapRegister message
Jian Li451175e2016-07-19 23:22:20 +090083 }
84
85 @Override
86 public Builder createBuilder() {
Jian Li525fded2016-08-04 01:15:33 +090087 return new DefaultRegisterBuilder();
Jian Li451175e2016-07-19 23:22:20 +090088 }
Jian Li719b3bf2016-07-22 00:38:29 +090089
90 @Override
91 public boolean isProxyMapReply() {
Jian Lif59c0ad2016-08-02 18:11:30 +090092 return proxyMapReply;
Jian Li719b3bf2016-07-22 00:38:29 +090093 }
94
95 @Override
96 public boolean isWantMapNotify() {
Jian Lif59c0ad2016-08-02 18:11:30 +090097 return wantMapNotify;
Jian Li719b3bf2016-07-22 00:38:29 +090098 }
99
100 @Override
101 public byte getRecordCount() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900102 return recordCount;
Jian Li719b3bf2016-07-22 00:38:29 +0900103 }
104
105 @Override
106 public long getNonce() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900107 return nonce;
Jian Li719b3bf2016-07-22 00:38:29 +0900108 }
109
110 @Override
111 public short getKeyId() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900112 return keyId;
Jian Li719b3bf2016-07-22 00:38:29 +0900113 }
114
115 @Override
Jian Liedc5db12016-08-23 17:30:19 +0900116 public short getAuthDataLength() {
117 return authDataLength;
118 }
119
120 @Override
Jian Li719b3bf2016-07-22 00:38:29 +0900121 public byte[] getAuthenticationData() {
Jian Lie4ba2a42016-08-29 20:24:15 +0900122 if (authenticationData != null && authenticationData.length != 0) {
123 return ImmutableByteSequence.copyFrom(authenticationData).asArray();
124 } else {
125 return new byte[0];
126 }
Jian Li719b3bf2016-07-22 00:38:29 +0900127 }
128
129 @Override
Jian Lia7b394d2016-08-21 23:11:46 +0900130 public List<LispMapRecord> getMapRecords() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900131 return ImmutableList.copyOf(mapRecords);
Jian Li719b3bf2016-07-22 00:38:29 +0900132 }
133
Jian Li20850d32016-08-04 02:15:57 +0900134 @Override
135 public String toString() {
136 return toStringHelper(this)
137 .add("type", getType())
138 .add("nonce", nonce)
139 .add("recordCount", recordCount)
140 .add("keyId", keyId)
Jian Liedc5db12016-08-23 17:30:19 +0900141 .add("authentication data length", authDataLength)
142 .add("authentication data", authenticationData)
Jian Li20850d32016-08-04 02:15:57 +0900143 .add("mapRecords", mapRecords)
144 .add("proxyMapReply", proxyMapReply)
145 .add("wantMapNotify", wantMapNotify).toString();
146 }
147
148 @Override
149 public boolean equals(Object o) {
150 if (this == o) {
151 return true;
152 }
153 if (o == null || getClass() != o.getClass()) {
154 return false;
155 }
156
157 DefaultLispMapRegister that = (DefaultLispMapRegister) o;
158 return Objects.equal(nonce, that.nonce) &&
159 Objects.equal(recordCount, that.recordCount) &&
160 Objects.equal(keyId, that.keyId) &&
Jian Liedc5db12016-08-23 17:30:19 +0900161 Objects.equal(authDataLength, that.authDataLength) &&
Jian Lie4ba2a42016-08-29 20:24:15 +0900162 Arrays.equals(authenticationData, that.authenticationData) &&
Jian Li20850d32016-08-04 02:15:57 +0900163 Objects.equal(proxyMapReply, that.proxyMapReply) &&
164 Objects.equal(wantMapNotify, that.wantMapNotify);
165 }
166
167 @Override
168 public int hashCode() {
Jian Liedc5db12016-08-23 17:30:19 +0900169 return Objects.hashCode(nonce, recordCount, keyId, authDataLength,
Jian Lie4ba2a42016-08-29 20:24:15 +0900170 proxyMapReply, wantMapNotify) + Arrays.hashCode(authenticationData);
Jian Li20850d32016-08-04 02:15:57 +0900171 }
172
Jian Li719b3bf2016-07-22 00:38:29 +0900173 public static final class DefaultRegisterBuilder implements RegisterBuilder {
174
Jian Lif59c0ad2016-08-02 18:11:30 +0900175 private long nonce;
176 private short keyId;
Jian Liedc5db12016-08-23 17:30:19 +0900177 private short authDataLength;
Jian Lif59c0ad2016-08-02 18:11:30 +0900178 private byte[] authenticationData;
179 private byte recordCount;
Jian Li47671902016-08-11 01:18:18 +0900180 private List<LispMapRecord> mapRecords;
Jian Lif59c0ad2016-08-02 18:11:30 +0900181 private boolean proxyMapReply;
182 private boolean wantMapNotify;
Jian Li719b3bf2016-07-22 00:38:29 +0900183
184 @Override
185 public LispType getType() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900186 return LispType.LISP_MAP_REGISTER;
Jian Li719b3bf2016-07-22 00:38:29 +0900187 }
188
189 @Override
Jian Lif59c0ad2016-08-02 18:11:30 +0900190 public RegisterBuilder withIsProxyMapReply(boolean proxyMapReply) {
191 this.proxyMapReply = proxyMapReply;
192 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900193 }
194
195 @Override
Jian Lif59c0ad2016-08-02 18:11:30 +0900196 public RegisterBuilder withIsWantMapNotify(boolean wantMapNotify) {
197 this.wantMapNotify = wantMapNotify;
198 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900199 }
200
201 @Override
202 public RegisterBuilder withRecordCount(byte recordCount) {
Jian Lif59c0ad2016-08-02 18:11:30 +0900203 this.recordCount = recordCount;
204 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900205 }
206
207 @Override
208 public RegisterBuilder withNonce(long nonce) {
Jian Lif59c0ad2016-08-02 18:11:30 +0900209 this.nonce = nonce;
210 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900211 }
212
213 @Override
Jian Liedc5db12016-08-23 17:30:19 +0900214 public RegisterBuilder withAuthDataLength(short authDataLength) {
215 this.authDataLength = authDataLength;
216 return this;
217 }
218
219 @Override
Jian Li719b3bf2016-07-22 00:38:29 +0900220 public RegisterBuilder withKeyId(short keyId) {
Jian Lif59c0ad2016-08-02 18:11:30 +0900221 this.keyId = keyId;
222 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900223 }
224
225 @Override
226 public RegisterBuilder withAuthenticationData(byte[] authenticationData) {
Jian Lie4ba2a42016-08-29 20:24:15 +0900227 if (authenticationData != null) {
228 this.authenticationData = authenticationData;
229 } else {
230 this.authenticationData = new byte[0];
231 }
Jian Lif59c0ad2016-08-02 18:11:30 +0900232 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900233 }
234
235 @Override
Jian Li47671902016-08-11 01:18:18 +0900236 public RegisterBuilder withMapRecords(List<LispMapRecord> mapRecords) {
Jian Lie4ba2a42016-08-29 20:24:15 +0900237 if (mapRecords != null) {
238 this.mapRecords = ImmutableList.copyOf(mapRecords);
239 } else {
240 this.mapRecords = Lists.newArrayList();
241 }
Jian Lif59c0ad2016-08-02 18:11:30 +0900242 return this;
243 }
244
245 @Override
Jian Li525fded2016-08-04 01:15:33 +0900246 public LispMapRegister build() {
Jian Lie4ba2a42016-08-29 20:24:15 +0900247 if (authenticationData == null) {
248 authenticationData = new byte[0];
249 }
250
251 if (mapRecords == null) {
252 mapRecords = Lists.newArrayList();
253 }
254
Jian Liedc5db12016-08-23 17:30:19 +0900255 return new DefaultLispMapRegister(nonce, keyId, authDataLength,
256 authenticationData, recordCount, mapRecords, proxyMapReply, wantMapNotify);
Jian Li719b3bf2016-07-22 00:38:29 +0900257 }
258 }
Jian Li26069e22016-08-10 22:00:52 +0900259
260 /**
Jian Liedc5db12016-08-23 17:30:19 +0900261 * A LISP message reader for MapRegister message.
Jian Li26069e22016-08-10 22:00:52 +0900262 */
Jian Liedc5db12016-08-23 17:30:19 +0900263 public static final class RegisterReader implements LispMessageReader<LispMapRegister> {
Jian Li26069e22016-08-10 22:00:52 +0900264
Jian Li47671902016-08-11 01:18:18 +0900265 private static final int PROXY_MAP_REPLY_INDEX = 3;
266 private static final int WANT_MAP_NOTIFY_INDEX = 0;
267 private static final int RESERVED_SKIP_LENGTH = 1;
268
Jian Li26069e22016-08-10 22:00:52 +0900269 @Override
Jian Lia7b394d2016-08-21 23:11:46 +0900270 public LispMapRegister readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException {
Jian Li47671902016-08-11 01:18:18 +0900271
272 if (byteBuf.readerIndex() != 0) {
273 return null;
274 }
275
276 // proxyMapReply -> 1 bit
277 boolean proxyMapReplyFlag = ByteOperator.getBit(byteBuf.readByte(), PROXY_MAP_REPLY_INDEX);
278
279 // let's skip the reserved field
280 byteBuf.skipBytes(RESERVED_SKIP_LENGTH);
281
282 byte reservedWithFlag = byteBuf.readByte();
283
284 // wantMapReply -> 1 bit
285 boolean wantMapNotifyFlag = ByteOperator.getBit(reservedWithFlag, WANT_MAP_NOTIFY_INDEX);
286
287 // record count -> 8 bits
288 byte recordCount = (byte) byteBuf.readUnsignedByte();
289
290 // nonce -> 64 bits
291 long nonce = byteBuf.readLong();
292
293 // keyId -> 16 bits
294 short keyId = byteBuf.readShort();
295
296 // authenticationDataLength -> 16 bits
297 short authLength = byteBuf.readShort();
298
299 // authenticationData -> depends on the authenticationDataLength
300 byte[] authData = new byte[authLength];
301 byteBuf.readBytes(authData);
302
303 List<LispMapRecord> mapRecords = Lists.newArrayList();
304 for (int i = 0; i < recordCount; i++) {
Jian Lie4ba2a42016-08-29 20:24:15 +0900305 mapRecords.add(new MapRecordReader().readFrom(byteBuf));
Jian Li47671902016-08-11 01:18:18 +0900306 }
307
308 return new DefaultRegisterBuilder()
309 .withIsProxyMapReply(proxyMapReplyFlag)
310 .withIsWantMapNotify(wantMapNotifyFlag)
311 .withRecordCount(recordCount)
312 .withNonce(nonce)
313 .withKeyId(keyId)
314 .withAuthenticationData(authData)
315 .withMapRecords(mapRecords)
316 .build();
Jian Li26069e22016-08-10 22:00:52 +0900317 }
318 }
Jian Liedc5db12016-08-23 17:30:19 +0900319
320 /**
321 * LISP map register message writer class.
322 */
323 public static class RegisterWriter implements LispMessageWriter<LispMapRegister> {
324
325 private static final int REGISTER_MSG_TYPE = 3;
326 private static final int REGISTER_SHIFT_BIT = 4;
327
328 private static final int PROXY_MAP_REPLY_SHIFT_BIT = 3;
329
330 private static final int ENABLE_BIT = 1;
331 private static final int DISABLE_BIT = 0;
332
333 private static final int UNUSED_ZERO = 0;
334
335 @Override
336 public void writeTo(ByteBuf byteBuf, LispMapRegister message) throws LispWriterException {
337
338 // specify LISP message type
339 byte msgType = (byte) (REGISTER_MSG_TYPE << REGISTER_SHIFT_BIT);
340
341 // proxy map reply flag
342 byte proxyMapReply = DISABLE_BIT;
343 if (message.isProxyMapReply()) {
344 proxyMapReply = (byte) (ENABLE_BIT << PROXY_MAP_REPLY_SHIFT_BIT);
345 }
346
347 byteBuf.writeByte(msgType + proxyMapReply);
348
349 // fill zero into reserved field
350 byteBuf.writeByte((short) UNUSED_ZERO);
351
352 // want map notify flag
353 byte wantMapNotify = DISABLE_BIT;
354 if (message.isWantMapNotify()) {
355 wantMapNotify = (byte) ENABLE_BIT;
356 }
357
358 byteBuf.writeByte(wantMapNotify);
359
360 // record count
361 byteBuf.writeByte(message.getRecordCount());
362
363 // nonce
364 byteBuf.writeLong(message.getNonce());
365
366 // keyId
367 byteBuf.writeShort(message.getKeyId());
368
369 // authentication data length in octet
370 byteBuf.writeShort(message.getAuthDataLength());
371
372 // authentication data
373 byte[] data = message.getAuthenticationData();
374 byte[] clone;
375 if (data != null) {
376 clone = data.clone();
377 Arrays.fill(clone, (byte) UNUSED_ZERO);
378 }
379
380 byteBuf.writeBytes(data);
381
382 // TODO: need to implement MAC authentication mechanism
383
384 // serialize map records
Jian Lie4ba2a42016-08-29 20:24:15 +0900385 MapRecordWriter writer = new MapRecordWriter();
Jian Liedc5db12016-08-23 17:30:19 +0900386 List<LispMapRecord> records = message.getMapRecords();
387
388 for (int i = 0; i < records.size(); i++) {
389 writer.writeTo(byteBuf, records.get(i));
390 }
391 }
392 }
Jian Li451175e2016-07-19 23:22:20 +0900393}