blob: 3171d2e8922396f01be0a42d3c114e760d124e30 [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 Lid1a109e2016-11-12 09:00:42 +090022import io.netty.buffer.Unpooled;
Jian Li47671902016-08-11 01:18:18 +090023import org.onlab.util.ByteOperator;
Jian Lif59c0ad2016-08-02 18:11:30 +090024import org.onlab.util.ImmutableByteSequence;
Jian Lid1a109e2016-11-12 09:00:42 +090025import org.onosproject.lisp.msg.authentication.LispAuthenticationFactory;
26import org.onosproject.lisp.msg.authentication.LispAuthenticationKeyEnum;
Jian Li26069e22016-08-10 22:00:52 +090027import org.onosproject.lisp.msg.exceptions.LispParseError;
Jian Lia7b394d2016-08-21 23:11:46 +090028import org.onosproject.lisp.msg.exceptions.LispReaderException;
Jian Liedc5db12016-08-23 17:30:19 +090029import org.onosproject.lisp.msg.exceptions.LispWriterException;
Jian Lid1a109e2016-11-12 09:00:42 +090030import org.slf4j.Logger;
31import org.slf4j.LoggerFactory;
Jian Li451175e2016-07-19 23:22:20 +090032
Jian Liedc5db12016-08-23 17:30:19 +090033import java.util.Arrays;
Jian Li719b3bf2016-07-22 00:38:29 +090034import java.util.List;
35
Jian Li20850d32016-08-04 02:15:57 +090036import static com.google.common.base.MoreObjects.toStringHelper;
Jian Lid1a109e2016-11-12 09:00:42 +090037import static org.onosproject.lisp.msg.authentication.LispAuthenticationKeyEnum.valueOf;
Jian Lie4ba2a42016-08-29 20:24:15 +090038import static org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.MapRecordReader;
39import static org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.MapRecordWriter;
Jian Li20850d32016-08-04 02:15:57 +090040
Jian Liedc5db12016-08-23 17:30:19 +090041
Jian Li451175e2016-07-19 23:22:20 +090042/**
43 * Default LISP map register message class.
44 */
Jian Liafe2d3f2016-11-01 02:49:07 +090045public final class DefaultLispMapRegister extends AbstractLispMessage
46 implements LispMapRegister {
Jian Lif59c0ad2016-08-02 18:11:30 +090047
Jian Lid1a109e2016-11-12 09:00:42 +090048 private static final Logger log = LoggerFactory.getLogger(DefaultLispMapRegister.class);
49
Jian Lif59c0ad2016-08-02 18:11:30 +090050 private final long nonce;
51 private final short keyId;
Jian Liedc5db12016-08-23 17:30:19 +090052 private final short authDataLength;
Jian Lid1a109e2016-11-12 09:00:42 +090053 private final byte[] authData;
Jian Lif59c0ad2016-08-02 18:11:30 +090054 private final List<LispMapRecord> mapRecords;
55 private final boolean proxyMapReply;
56 private final boolean wantMapNotify;
57
Yoonseon Hanca814bf2016-09-12 11:37:48 -070058 static final RegisterWriter WRITER;
Jian Lid1a109e2016-11-12 09:00:42 +090059
Yoonseon Hanca814bf2016-09-12 11:37:48 -070060 static {
61 WRITER = new RegisterWriter();
62 }
63
Jian Lif59c0ad2016-08-02 18:11:30 +090064 /**
65 * A private constructor that protects object instantiation from external.
66 *
Jian Lid1a109e2016-11-12 09:00:42 +090067 * @param nonce nonce
68 * @param keyId key identifier
69 * @param authDataLength authentication data length
70 * @param authData authentication data
71 * @param mapRecords a collection of map records
72 * @param proxyMapReply proxy map reply flag
73 * @param wantMapNotify want map notify flag
Jian Lif59c0ad2016-08-02 18:11:30 +090074 */
Jian Liedc5db12016-08-23 17:30:19 +090075 private DefaultLispMapRegister(long nonce, short keyId, short authDataLength,
Jian Lid1a109e2016-11-12 09:00:42 +090076 byte[] authData, List<LispMapRecord> mapRecords,
Jian Lif59c0ad2016-08-02 18:11:30 +090077 boolean proxyMapReply, boolean wantMapNotify) {
78 this.nonce = nonce;
79 this.keyId = keyId;
Jian Liedc5db12016-08-23 17:30:19 +090080 this.authDataLength = authDataLength;
Jian Lid1a109e2016-11-12 09:00:42 +090081 this.authData = authData;
Jian Lif59c0ad2016-08-02 18:11:30 +090082 this.mapRecords = mapRecords;
83 this.proxyMapReply = proxyMapReply;
84 this.wantMapNotify = wantMapNotify;
85 }
86
Jian Li451175e2016-07-19 23:22:20 +090087 @Override
88 public LispType getType() {
Jian Lif59c0ad2016-08-02 18:11:30 +090089 return LispType.LISP_MAP_REGISTER;
Jian Li451175e2016-07-19 23:22:20 +090090 }
91
92 @Override
Yoonseon Hanca814bf2016-09-12 11:37:48 -070093 public void writeTo(ByteBuf byteBuf) throws LispWriterException {
94 WRITER.writeTo(byteBuf, this);
Jian Li451175e2016-07-19 23:22:20 +090095 }
96
97 @Override
98 public Builder createBuilder() {
Jian Li525fded2016-08-04 01:15:33 +090099 return new DefaultRegisterBuilder();
Jian Li451175e2016-07-19 23:22:20 +0900100 }
Jian Li719b3bf2016-07-22 00:38:29 +0900101
102 @Override
103 public boolean isProxyMapReply() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900104 return proxyMapReply;
Jian Li719b3bf2016-07-22 00:38:29 +0900105 }
106
107 @Override
108 public boolean isWantMapNotify() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900109 return wantMapNotify;
Jian Li719b3bf2016-07-22 00:38:29 +0900110 }
111
112 @Override
Jian Li42b3e432016-08-31 01:05:20 +0900113 public int getRecordCount() {
114 return mapRecords.size();
Jian Li719b3bf2016-07-22 00:38:29 +0900115 }
116
117 @Override
118 public long getNonce() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900119 return nonce;
Jian Li719b3bf2016-07-22 00:38:29 +0900120 }
121
122 @Override
123 public short getKeyId() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900124 return keyId;
Jian Li719b3bf2016-07-22 00:38:29 +0900125 }
126
127 @Override
Jian Liedc5db12016-08-23 17:30:19 +0900128 public short getAuthDataLength() {
129 return authDataLength;
130 }
131
132 @Override
Jian Lid1a109e2016-11-12 09:00:42 +0900133 public byte[] getAuthData() {
134 if (authData != null && authData.length != 0) {
135 return ImmutableByteSequence.copyFrom(authData).asArray();
Jian Lie4ba2a42016-08-29 20:24:15 +0900136 } else {
137 return new byte[0];
138 }
Jian Li719b3bf2016-07-22 00:38:29 +0900139 }
140
141 @Override
Jian Lia7b394d2016-08-21 23:11:46 +0900142 public List<LispMapRecord> getMapRecords() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900143 return ImmutableList.copyOf(mapRecords);
Jian Li719b3bf2016-07-22 00:38:29 +0900144 }
145
Jian Li20850d32016-08-04 02:15:57 +0900146 @Override
147 public String toString() {
148 return toStringHelper(this)
149 .add("type", getType())
150 .add("nonce", nonce)
Jian Li20850d32016-08-04 02:15:57 +0900151 .add("keyId", keyId)
Jian Liedc5db12016-08-23 17:30:19 +0900152 .add("authentication data length", authDataLength)
Jian Lid1a109e2016-11-12 09:00:42 +0900153 .add("authentication data", authData)
Jian Li20850d32016-08-04 02:15:57 +0900154 .add("mapRecords", mapRecords)
155 .add("proxyMapReply", proxyMapReply)
156 .add("wantMapNotify", wantMapNotify).toString();
157 }
158
159 @Override
160 public boolean equals(Object o) {
161 if (this == o) {
162 return true;
163 }
164 if (o == null || getClass() != o.getClass()) {
165 return false;
166 }
167
168 DefaultLispMapRegister that = (DefaultLispMapRegister) o;
169 return Objects.equal(nonce, that.nonce) &&
Jian Li20850d32016-08-04 02:15:57 +0900170 Objects.equal(keyId, that.keyId) &&
Jian Liedc5db12016-08-23 17:30:19 +0900171 Objects.equal(authDataLength, that.authDataLength) &&
Jian Lid1a109e2016-11-12 09:00:42 +0900172 Arrays.equals(authData, that.authData) &&
Jian Li20850d32016-08-04 02:15:57 +0900173 Objects.equal(proxyMapReply, that.proxyMapReply) &&
174 Objects.equal(wantMapNotify, that.wantMapNotify);
175 }
176
177 @Override
178 public int hashCode() {
Jian Li42b3e432016-08-31 01:05:20 +0900179 return Objects.hashCode(nonce, keyId, authDataLength,
Jian Lid1a109e2016-11-12 09:00:42 +0900180 proxyMapReply, wantMapNotify) + Arrays.hashCode(authData);
Jian Li20850d32016-08-04 02:15:57 +0900181 }
182
Jian Li719b3bf2016-07-22 00:38:29 +0900183 public static final class DefaultRegisterBuilder implements RegisterBuilder {
184
Jian Lif59c0ad2016-08-02 18:11:30 +0900185 private long nonce;
186 private short keyId;
Jian Liedc5db12016-08-23 17:30:19 +0900187 private short authDataLength;
Jian Lid1a109e2016-11-12 09:00:42 +0900188 private byte[] authData;
189 private String authKey;
Jian Lid4e63702016-08-30 18:29:20 +0900190 private List<LispMapRecord> mapRecords = Lists.newArrayList();
Jian Lif59c0ad2016-08-02 18:11:30 +0900191 private boolean proxyMapReply;
192 private boolean wantMapNotify;
Jian Li719b3bf2016-07-22 00:38:29 +0900193
194 @Override
195 public LispType getType() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900196 return LispType.LISP_MAP_REGISTER;
Jian Li719b3bf2016-07-22 00:38:29 +0900197 }
198
199 @Override
Jian Lif59c0ad2016-08-02 18:11:30 +0900200 public RegisterBuilder withIsProxyMapReply(boolean proxyMapReply) {
201 this.proxyMapReply = proxyMapReply;
202 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900203 }
204
205 @Override
Jian Lif59c0ad2016-08-02 18:11:30 +0900206 public RegisterBuilder withIsWantMapNotify(boolean wantMapNotify) {
207 this.wantMapNotify = wantMapNotify;
208 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900209 }
210
211 @Override
Jian Li719b3bf2016-07-22 00:38:29 +0900212 public RegisterBuilder withNonce(long nonce) {
Jian Lif59c0ad2016-08-02 18:11:30 +0900213 this.nonce = nonce;
214 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900215 }
216
217 @Override
Jian Lid1a109e2016-11-12 09:00:42 +0900218 public RegisterBuilder withAuthKey(String key) {
219 this.authKey = key;
220 return this;
221 }
222
223 @Override
Jian Liedc5db12016-08-23 17:30:19 +0900224 public RegisterBuilder withAuthDataLength(short authDataLength) {
225 this.authDataLength = authDataLength;
226 return this;
227 }
228
229 @Override
Jian Li719b3bf2016-07-22 00:38:29 +0900230 public RegisterBuilder withKeyId(short keyId) {
Jian Lif59c0ad2016-08-02 18:11:30 +0900231 this.keyId = keyId;
232 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900233 }
234
235 @Override
Jian Lid1a109e2016-11-12 09:00:42 +0900236 public RegisterBuilder withAuthData(byte[] authenticationData) {
Jian Lie4ba2a42016-08-29 20:24:15 +0900237 if (authenticationData != null) {
Jian Lid1a109e2016-11-12 09:00:42 +0900238 this.authData = authenticationData;
Jian Lie4ba2a42016-08-29 20:24:15 +0900239 }
Jian Lif59c0ad2016-08-02 18:11:30 +0900240 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900241 }
242
243 @Override
Jian Li47671902016-08-11 01:18:18 +0900244 public RegisterBuilder withMapRecords(List<LispMapRecord> mapRecords) {
Jian Lie4ba2a42016-08-29 20:24:15 +0900245 if (mapRecords != null) {
246 this.mapRecords = ImmutableList.copyOf(mapRecords);
Jian Lie4ba2a42016-08-29 20:24:15 +0900247 }
Jian Lif59c0ad2016-08-02 18:11:30 +0900248 return this;
249 }
250
251 @Override
Jian Li525fded2016-08-04 01:15:33 +0900252 public LispMapRegister build() {
Jian Lid1a109e2016-11-12 09:00:42 +0900253
254 // if authentication data is not specified, we will calculate it
255 if (authData == null) {
256 LispAuthenticationFactory factory = LispAuthenticationFactory.getInstance();
257
258 authDataLength = LispAuthenticationKeyEnum.valueOf(keyId).getHashLength();
259 byte[] tmpAuthData = new byte[authDataLength];
260 Arrays.fill(tmpAuthData, (byte) 0);
261 authData = tmpAuthData;
262
263 ByteBuf byteBuf = Unpooled.buffer();
264 try {
265 new DefaultLispMapRegister(nonce, keyId, authDataLength, authData,
266 mapRecords, proxyMapReply, wantMapNotify).writeTo(byteBuf);
267 } catch (LispWriterException e) {
268 log.warn("Failed to serialize map register message", e);
269 }
270
271 byte[] bytes = new byte[byteBuf.readableBytes()];
272 byteBuf.readBytes(bytes);
273
274 if (authKey == null) {
275 log.warn("Must specify authentication key");
276 }
277
278 authData = factory.createAuthenticationData(valueOf(keyId), authKey, bytes);
279 }
280
Jian Liedc5db12016-08-23 17:30:19 +0900281 return new DefaultLispMapRegister(nonce, keyId, authDataLength,
Jian Lid1a109e2016-11-12 09:00:42 +0900282 authData, mapRecords, proxyMapReply, wantMapNotify);
Jian Li719b3bf2016-07-22 00:38:29 +0900283 }
284 }
Jian Li26069e22016-08-10 22:00:52 +0900285
286 /**
Jian Liedc5db12016-08-23 17:30:19 +0900287 * A LISP message reader for MapRegister message.
Jian Li26069e22016-08-10 22:00:52 +0900288 */
Jian Liedc5db12016-08-23 17:30:19 +0900289 public static final class RegisterReader implements LispMessageReader<LispMapRegister> {
Jian Li26069e22016-08-10 22:00:52 +0900290
Jian Li47671902016-08-11 01:18:18 +0900291 private static final int PROXY_MAP_REPLY_INDEX = 3;
292 private static final int WANT_MAP_NOTIFY_INDEX = 0;
293 private static final int RESERVED_SKIP_LENGTH = 1;
294
Jian Li26069e22016-08-10 22:00:52 +0900295 @Override
Jian Lia7b394d2016-08-21 23:11:46 +0900296 public LispMapRegister readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException {
Jian Li47671902016-08-11 01:18:18 +0900297
298 if (byteBuf.readerIndex() != 0) {
299 return null;
300 }
301
302 // proxyMapReply -> 1 bit
303 boolean proxyMapReplyFlag = ByteOperator.getBit(byteBuf.readByte(), PROXY_MAP_REPLY_INDEX);
304
305 // let's skip the reserved field
306 byteBuf.skipBytes(RESERVED_SKIP_LENGTH);
307
308 byte reservedWithFlag = byteBuf.readByte();
309
310 // wantMapReply -> 1 bit
311 boolean wantMapNotifyFlag = ByteOperator.getBit(reservedWithFlag, WANT_MAP_NOTIFY_INDEX);
312
313 // record count -> 8 bits
314 byte recordCount = (byte) byteBuf.readUnsignedByte();
315
316 // nonce -> 64 bits
317 long nonce = byteBuf.readLong();
318
319 // keyId -> 16 bits
320 short keyId = byteBuf.readShort();
321
322 // authenticationDataLength -> 16 bits
323 short authLength = byteBuf.readShort();
324
Jian Lid1a109e2016-11-12 09:00:42 +0900325 // authData -> depends on the authenticationDataLength
Jian Li47671902016-08-11 01:18:18 +0900326 byte[] authData = new byte[authLength];
327 byteBuf.readBytes(authData);
328
329 List<LispMapRecord> mapRecords = Lists.newArrayList();
330 for (int i = 0; i < recordCount; i++) {
Jian Lie4ba2a42016-08-29 20:24:15 +0900331 mapRecords.add(new MapRecordReader().readFrom(byteBuf));
Jian Li47671902016-08-11 01:18:18 +0900332 }
333
334 return new DefaultRegisterBuilder()
335 .withIsProxyMapReply(proxyMapReplyFlag)
336 .withIsWantMapNotify(wantMapNotifyFlag)
Jian Li47671902016-08-11 01:18:18 +0900337 .withNonce(nonce)
338 .withKeyId(keyId)
Jian Lid1a109e2016-11-12 09:00:42 +0900339 .withAuthData(authData)
Jian Li88addd52016-10-31 02:05:08 +0900340 .withAuthDataLength(authLength)
Jian Li47671902016-08-11 01:18:18 +0900341 .withMapRecords(mapRecords)
342 .build();
Jian Li26069e22016-08-10 22:00:52 +0900343 }
344 }
Jian Liedc5db12016-08-23 17:30:19 +0900345
346 /**
347 * LISP map register message writer class.
348 */
349 public static class RegisterWriter implements LispMessageWriter<LispMapRegister> {
350
Jian Liedc5db12016-08-23 17:30:19 +0900351 private static final int REGISTER_SHIFT_BIT = 4;
352
353 private static final int PROXY_MAP_REPLY_SHIFT_BIT = 3;
354
355 private static final int ENABLE_BIT = 1;
356 private static final int DISABLE_BIT = 0;
357
358 private static final int UNUSED_ZERO = 0;
359
360 @Override
361 public void writeTo(ByteBuf byteBuf, LispMapRegister message) throws LispWriterException {
362
363 // specify LISP message type
Jian Licbc57e32016-09-14 09:06:54 +0900364 byte msgType = (byte) (LispType.LISP_MAP_REGISTER.getTypeCode() << REGISTER_SHIFT_BIT);
Jian Liedc5db12016-08-23 17:30:19 +0900365
366 // proxy map reply flag
367 byte proxyMapReply = DISABLE_BIT;
Jian Lid1a109e2016-11-12 09:00:42 +0900368 if (message.isProxyMapReply()) {
Jian Liedc5db12016-08-23 17:30:19 +0900369 proxyMapReply = (byte) (ENABLE_BIT << PROXY_MAP_REPLY_SHIFT_BIT);
370 }
371
372 byteBuf.writeByte(msgType + proxyMapReply);
373
374 // fill zero into reserved field
375 byteBuf.writeByte((short) UNUSED_ZERO);
376
377 // want map notify flag
378 byte wantMapNotify = DISABLE_BIT;
379 if (message.isWantMapNotify()) {
380 wantMapNotify = (byte) ENABLE_BIT;
381 }
382
383 byteBuf.writeByte(wantMapNotify);
384
385 // record count
Jian Li42b3e432016-08-31 01:05:20 +0900386 byteBuf.writeByte(message.getMapRecords().size());
Jian Liedc5db12016-08-23 17:30:19 +0900387
388 // nonce
389 byteBuf.writeLong(message.getNonce());
390
391 // keyId
392 byteBuf.writeShort(message.getKeyId());
393
Jian Lif8c2d4a2016-09-15 02:33:12 +0900394 // authentication data and its length
Jian Lid1a109e2016-11-12 09:00:42 +0900395 if (message.getAuthData() == null) {
Jian Lif8c2d4a2016-09-15 02:33:12 +0900396 byteBuf.writeShort((short) 0);
397 } else {
Jian Lid1a109e2016-11-12 09:00:42 +0900398 byteBuf.writeShort(message.getAuthData().length);
399 byteBuf.writeBytes(message.getAuthData());
Jian Liedc5db12016-08-23 17:30:19 +0900400 }
401
Jian Liedc5db12016-08-23 17:30:19 +0900402 // serialize map records
Jian Lie4ba2a42016-08-29 20:24:15 +0900403 MapRecordWriter writer = new MapRecordWriter();
Jian Liedc5db12016-08-23 17:30:19 +0900404 List<LispMapRecord> records = message.getMapRecords();
405
406 for (int i = 0; i < records.size(); i++) {
407 writer.writeTo(byteBuf, records.get(i));
408 }
409 }
410 }
Jian Li451175e2016-07-19 23:22:20 +0900411}