blob: a75d72d1425fc5b2ef5e61c68c0172d143485f9d [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;
Jian Li26069e22016-08-10 22:00:52 +090026import org.onosproject.lisp.msg.exceptions.LispParseError;
Jian Lia7b394d2016-08-21 23:11:46 +090027import org.onosproject.lisp.msg.exceptions.LispReaderException;
Jian Liedc5db12016-08-23 17:30:19 +090028import org.onosproject.lisp.msg.exceptions.LispWriterException;
Jian Li5e505c62016-12-05 02:44:24 +090029import org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.MapRecordReader;
30import org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.MapRecordWriter;
Jian Lid1a109e2016-11-12 09:00:42 +090031import org.slf4j.Logger;
32import org.slf4j.LoggerFactory;
Jian Li451175e2016-07-19 23:22:20 +090033
Jian Liedc5db12016-08-23 17:30:19 +090034import java.util.Arrays;
Jian Li719b3bf2016-07-22 00:38:29 +090035import java.util.List;
36
Jian Li20850d32016-08-04 02:15:57 +090037import static com.google.common.base.MoreObjects.toStringHelper;
Jian Lid1a109e2016-11-12 09:00:42 +090038import static org.onosproject.lisp.msg.authentication.LispAuthenticationKeyEnum.valueOf;
Jian Liedc5db12016-08-23 17:30:19 +090039
Jian Li451175e2016-07-19 23:22:20 +090040/**
41 * Default LISP map register message class.
42 */
Jian Liafe2d3f2016-11-01 02:49:07 +090043public final class DefaultLispMapRegister extends AbstractLispMessage
44 implements LispMapRegister {
Jian Lif59c0ad2016-08-02 18:11:30 +090045
Jian Lid1a109e2016-11-12 09:00:42 +090046 private static final Logger log = LoggerFactory.getLogger(DefaultLispMapRegister.class);
47
Jian Lif59c0ad2016-08-02 18:11:30 +090048 private final long nonce;
49 private final short keyId;
Jian Liedc5db12016-08-23 17:30:19 +090050 private final short authDataLength;
Jian Lid1a109e2016-11-12 09:00:42 +090051 private final byte[] authData;
Jian Lif59c0ad2016-08-02 18:11:30 +090052 private final List<LispMapRecord> mapRecords;
53 private final boolean proxyMapReply;
54 private final boolean wantMapNotify;
55
Yoonseon Hanca814bf2016-09-12 11:37:48 -070056 static final RegisterWriter WRITER;
Jian Lid1a109e2016-11-12 09:00:42 +090057
Yoonseon Hanca814bf2016-09-12 11:37:48 -070058 static {
59 WRITER = new RegisterWriter();
60 }
61
Jian Lif59c0ad2016-08-02 18:11:30 +090062 /**
63 * A private constructor that protects object instantiation from external.
64 *
Jian Lid1a109e2016-11-12 09:00:42 +090065 * @param nonce nonce
66 * @param keyId key identifier
67 * @param authDataLength authentication data length
68 * @param authData authentication data
69 * @param mapRecords a collection of map records
70 * @param proxyMapReply proxy map reply flag
71 * @param wantMapNotify want map notify flag
Jian Lif59c0ad2016-08-02 18:11:30 +090072 */
Jian Liedc5db12016-08-23 17:30:19 +090073 private DefaultLispMapRegister(long nonce, short keyId, short authDataLength,
Jian Lid1a109e2016-11-12 09:00:42 +090074 byte[] authData, List<LispMapRecord> mapRecords,
Jian Lif59c0ad2016-08-02 18:11:30 +090075 boolean proxyMapReply, boolean wantMapNotify) {
76 this.nonce = nonce;
77 this.keyId = keyId;
Jian Liedc5db12016-08-23 17:30:19 +090078 this.authDataLength = authDataLength;
Jian Lid1a109e2016-11-12 09:00:42 +090079 this.authData = authData;
Jian Lif59c0ad2016-08-02 18:11:30 +090080 this.mapRecords = mapRecords;
81 this.proxyMapReply = proxyMapReply;
82 this.wantMapNotify = wantMapNotify;
83 }
84
Jian Li451175e2016-07-19 23:22:20 +090085 @Override
86 public LispType getType() {
Jian Lif59c0ad2016-08-02 18:11:30 +090087 return LispType.LISP_MAP_REGISTER;
Jian Li451175e2016-07-19 23:22:20 +090088 }
89
90 @Override
Yoonseon Hanca814bf2016-09-12 11:37:48 -070091 public void writeTo(ByteBuf byteBuf) throws LispWriterException {
92 WRITER.writeTo(byteBuf, this);
Jian Li451175e2016-07-19 23:22:20 +090093 }
94
95 @Override
96 public Builder createBuilder() {
Jian Li525fded2016-08-04 01:15:33 +090097 return new DefaultRegisterBuilder();
Jian Li451175e2016-07-19 23:22:20 +090098 }
Jian Li719b3bf2016-07-22 00:38:29 +090099
100 @Override
101 public boolean isProxyMapReply() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900102 return proxyMapReply;
Jian Li719b3bf2016-07-22 00:38:29 +0900103 }
104
105 @Override
106 public boolean isWantMapNotify() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900107 return wantMapNotify;
Jian Li719b3bf2016-07-22 00:38:29 +0900108 }
109
110 @Override
Jian Li42b3e432016-08-31 01:05:20 +0900111 public int getRecordCount() {
112 return mapRecords.size();
Jian Li719b3bf2016-07-22 00:38:29 +0900113 }
114
115 @Override
116 public long getNonce() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900117 return nonce;
Jian Li719b3bf2016-07-22 00:38:29 +0900118 }
119
120 @Override
121 public short getKeyId() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900122 return keyId;
Jian Li719b3bf2016-07-22 00:38:29 +0900123 }
124
125 @Override
Jian Liedc5db12016-08-23 17:30:19 +0900126 public short getAuthDataLength() {
127 return authDataLength;
128 }
129
130 @Override
Jian Lid1a109e2016-11-12 09:00:42 +0900131 public byte[] getAuthData() {
132 if (authData != null && authData.length != 0) {
133 return ImmutableByteSequence.copyFrom(authData).asArray();
Jian Lie4ba2a42016-08-29 20:24:15 +0900134 } else {
135 return new byte[0];
136 }
Jian Li719b3bf2016-07-22 00:38:29 +0900137 }
138
139 @Override
Jian Lia7b394d2016-08-21 23:11:46 +0900140 public List<LispMapRecord> getMapRecords() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900141 return ImmutableList.copyOf(mapRecords);
Jian Li719b3bf2016-07-22 00:38:29 +0900142 }
143
Jian Li20850d32016-08-04 02:15:57 +0900144 @Override
145 public String toString() {
146 return toStringHelper(this)
147 .add("type", getType())
148 .add("nonce", nonce)
Jian Li20850d32016-08-04 02:15:57 +0900149 .add("keyId", keyId)
Jian Liedc5db12016-08-23 17:30:19 +0900150 .add("authentication data length", authDataLength)
Jian Lid1a109e2016-11-12 09:00:42 +0900151 .add("authentication data", authData)
Jian Li20850d32016-08-04 02:15:57 +0900152 .add("mapRecords", mapRecords)
153 .add("proxyMapReply", proxyMapReply)
154 .add("wantMapNotify", wantMapNotify).toString();
155 }
156
157 @Override
158 public boolean equals(Object o) {
159 if (this == o) {
160 return true;
161 }
162 if (o == null || getClass() != o.getClass()) {
163 return false;
164 }
165
166 DefaultLispMapRegister that = (DefaultLispMapRegister) o;
167 return Objects.equal(nonce, that.nonce) &&
Jian Li20850d32016-08-04 02:15:57 +0900168 Objects.equal(keyId, that.keyId) &&
Jian Liedc5db12016-08-23 17:30:19 +0900169 Objects.equal(authDataLength, that.authDataLength) &&
Jian Lid1a109e2016-11-12 09:00:42 +0900170 Arrays.equals(authData, that.authData) &&
Jian Li20850d32016-08-04 02:15:57 +0900171 Objects.equal(proxyMapReply, that.proxyMapReply) &&
172 Objects.equal(wantMapNotify, that.wantMapNotify);
173 }
174
175 @Override
176 public int hashCode() {
Jian Li42b3e432016-08-31 01:05:20 +0900177 return Objects.hashCode(nonce, keyId, authDataLength,
Jian Lid1a109e2016-11-12 09:00:42 +0900178 proxyMapReply, wantMapNotify) + Arrays.hashCode(authData);
Jian Li20850d32016-08-04 02:15:57 +0900179 }
180
Jian Li719b3bf2016-07-22 00:38:29 +0900181 public static final class DefaultRegisterBuilder implements RegisterBuilder {
182
Jian Lif59c0ad2016-08-02 18:11:30 +0900183 private long nonce;
184 private short keyId;
Jian Liedc5db12016-08-23 17:30:19 +0900185 private short authDataLength;
Jian Lid1a109e2016-11-12 09:00:42 +0900186 private byte[] authData;
187 private String authKey;
Jian Lid4e63702016-08-30 18:29:20 +0900188 private List<LispMapRecord> mapRecords = Lists.newArrayList();
Jian Lif59c0ad2016-08-02 18:11:30 +0900189 private boolean proxyMapReply;
190 private boolean wantMapNotify;
Jian Li719b3bf2016-07-22 00:38:29 +0900191
192 @Override
193 public LispType getType() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900194 return LispType.LISP_MAP_REGISTER;
Jian Li719b3bf2016-07-22 00:38:29 +0900195 }
196
197 @Override
Jian Lif59c0ad2016-08-02 18:11:30 +0900198 public RegisterBuilder withIsProxyMapReply(boolean proxyMapReply) {
199 this.proxyMapReply = proxyMapReply;
200 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900201 }
202
203 @Override
Jian Lif59c0ad2016-08-02 18:11:30 +0900204 public RegisterBuilder withIsWantMapNotify(boolean wantMapNotify) {
205 this.wantMapNotify = wantMapNotify;
206 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900207 }
208
209 @Override
Jian Li719b3bf2016-07-22 00:38:29 +0900210 public RegisterBuilder withNonce(long nonce) {
Jian Lif59c0ad2016-08-02 18:11:30 +0900211 this.nonce = nonce;
212 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900213 }
214
215 @Override
Jian Lid1a109e2016-11-12 09:00:42 +0900216 public RegisterBuilder withAuthKey(String key) {
217 this.authKey = key;
218 return this;
219 }
220
221 @Override
Jian Liedc5db12016-08-23 17:30:19 +0900222 public RegisterBuilder withAuthDataLength(short authDataLength) {
223 this.authDataLength = authDataLength;
224 return this;
225 }
226
227 @Override
Jian Li719b3bf2016-07-22 00:38:29 +0900228 public RegisterBuilder withKeyId(short keyId) {
Jian Lif59c0ad2016-08-02 18:11:30 +0900229 this.keyId = keyId;
230 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900231 }
232
233 @Override
Jian Lid1a109e2016-11-12 09:00:42 +0900234 public RegisterBuilder withAuthData(byte[] authenticationData) {
Jian Lie4ba2a42016-08-29 20:24:15 +0900235 if (authenticationData != null) {
Jian Lid1a109e2016-11-12 09:00:42 +0900236 this.authData = authenticationData;
Jian Lie4ba2a42016-08-29 20:24:15 +0900237 }
Jian Lif59c0ad2016-08-02 18:11:30 +0900238 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900239 }
240
241 @Override
Jian Li47671902016-08-11 01:18:18 +0900242 public RegisterBuilder withMapRecords(List<LispMapRecord> mapRecords) {
Jian Lie4ba2a42016-08-29 20:24:15 +0900243 if (mapRecords != null) {
244 this.mapRecords = ImmutableList.copyOf(mapRecords);
Jian Lie4ba2a42016-08-29 20:24:15 +0900245 }
Jian Lif59c0ad2016-08-02 18:11:30 +0900246 return this;
247 }
248
249 @Override
Jian Li525fded2016-08-04 01:15:33 +0900250 public LispMapRegister build() {
Jian Lid1a109e2016-11-12 09:00:42 +0900251
252 // if authentication data is not specified, we will calculate it
253 if (authData == null) {
254 LispAuthenticationFactory factory = LispAuthenticationFactory.getInstance();
255
Jian Li5e505c62016-12-05 02:44:24 +0900256 authDataLength = valueOf(keyId).getHashLength();
Jian Lid1a109e2016-11-12 09:00:42 +0900257 byte[] tmpAuthData = new byte[authDataLength];
258 Arrays.fill(tmpAuthData, (byte) 0);
259 authData = tmpAuthData;
260
261 ByteBuf byteBuf = Unpooled.buffer();
262 try {
263 new DefaultLispMapRegister(nonce, keyId, authDataLength, authData,
264 mapRecords, proxyMapReply, wantMapNotify).writeTo(byteBuf);
265 } catch (LispWriterException e) {
266 log.warn("Failed to serialize map register message", e);
267 }
268
269 byte[] bytes = new byte[byteBuf.readableBytes()];
270 byteBuf.readBytes(bytes);
271
272 if (authKey == null) {
273 log.warn("Must specify authentication key");
274 }
275
276 authData = factory.createAuthenticationData(valueOf(keyId), authKey, bytes);
277 }
278
Jian Liedc5db12016-08-23 17:30:19 +0900279 return new DefaultLispMapRegister(nonce, keyId, authDataLength,
Jian Lid1a109e2016-11-12 09:00:42 +0900280 authData, mapRecords, proxyMapReply, wantMapNotify);
Jian Li719b3bf2016-07-22 00:38:29 +0900281 }
282 }
Jian Li26069e22016-08-10 22:00:52 +0900283
284 /**
Jian Liedc5db12016-08-23 17:30:19 +0900285 * A LISP message reader for MapRegister message.
Jian Li26069e22016-08-10 22:00:52 +0900286 */
Jian Liedc5db12016-08-23 17:30:19 +0900287 public static final class RegisterReader implements LispMessageReader<LispMapRegister> {
Jian Li26069e22016-08-10 22:00:52 +0900288
Jian Li47671902016-08-11 01:18:18 +0900289 private static final int PROXY_MAP_REPLY_INDEX = 3;
290 private static final int WANT_MAP_NOTIFY_INDEX = 0;
291 private static final int RESERVED_SKIP_LENGTH = 1;
292
Jian Li26069e22016-08-10 22:00:52 +0900293 @Override
Jian Lia7b394d2016-08-21 23:11:46 +0900294 public LispMapRegister readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException {
Jian Li47671902016-08-11 01:18:18 +0900295
296 if (byteBuf.readerIndex() != 0) {
297 return null;
298 }
299
300 // proxyMapReply -> 1 bit
301 boolean proxyMapReplyFlag = ByteOperator.getBit(byteBuf.readByte(), PROXY_MAP_REPLY_INDEX);
302
303 // let's skip the reserved field
304 byteBuf.skipBytes(RESERVED_SKIP_LENGTH);
305
306 byte reservedWithFlag = byteBuf.readByte();
307
308 // wantMapReply -> 1 bit
309 boolean wantMapNotifyFlag = ByteOperator.getBit(reservedWithFlag, WANT_MAP_NOTIFY_INDEX);
310
311 // record count -> 8 bits
312 byte recordCount = (byte) byteBuf.readUnsignedByte();
313
314 // nonce -> 64 bits
315 long nonce = byteBuf.readLong();
316
317 // keyId -> 16 bits
318 short keyId = byteBuf.readShort();
319
320 // authenticationDataLength -> 16 bits
321 short authLength = byteBuf.readShort();
322
Jian Lid1a109e2016-11-12 09:00:42 +0900323 // authData -> depends on the authenticationDataLength
Jian Li47671902016-08-11 01:18:18 +0900324 byte[] authData = new byte[authLength];
325 byteBuf.readBytes(authData);
326
327 List<LispMapRecord> mapRecords = Lists.newArrayList();
328 for (int i = 0; i < recordCount; i++) {
Jian Lie4ba2a42016-08-29 20:24:15 +0900329 mapRecords.add(new MapRecordReader().readFrom(byteBuf));
Jian Li47671902016-08-11 01:18:18 +0900330 }
331
332 return new DefaultRegisterBuilder()
333 .withIsProxyMapReply(proxyMapReplyFlag)
334 .withIsWantMapNotify(wantMapNotifyFlag)
Jian Li47671902016-08-11 01:18:18 +0900335 .withNonce(nonce)
336 .withKeyId(keyId)
Jian Lid1a109e2016-11-12 09:00:42 +0900337 .withAuthData(authData)
Jian Li88addd52016-10-31 02:05:08 +0900338 .withAuthDataLength(authLength)
Jian Li47671902016-08-11 01:18:18 +0900339 .withMapRecords(mapRecords)
340 .build();
Jian Li26069e22016-08-10 22:00:52 +0900341 }
342 }
Jian Liedc5db12016-08-23 17:30:19 +0900343
344 /**
345 * LISP map register message writer class.
346 */
347 public static class RegisterWriter implements LispMessageWriter<LispMapRegister> {
348
Jian Liedc5db12016-08-23 17:30:19 +0900349 private static final int REGISTER_SHIFT_BIT = 4;
350
351 private static final int PROXY_MAP_REPLY_SHIFT_BIT = 3;
352
353 private static final int ENABLE_BIT = 1;
354 private static final int DISABLE_BIT = 0;
355
356 private static final int UNUSED_ZERO = 0;
357
358 @Override
359 public void writeTo(ByteBuf byteBuf, LispMapRegister message) throws LispWriterException {
360
361 // specify LISP message type
Jian Licbc57e32016-09-14 09:06:54 +0900362 byte msgType = (byte) (LispType.LISP_MAP_REGISTER.getTypeCode() << REGISTER_SHIFT_BIT);
Jian Liedc5db12016-08-23 17:30:19 +0900363
364 // proxy map reply flag
365 byte proxyMapReply = DISABLE_BIT;
Jian Lid1a109e2016-11-12 09:00:42 +0900366 if (message.isProxyMapReply()) {
Jian Liedc5db12016-08-23 17:30:19 +0900367 proxyMapReply = (byte) (ENABLE_BIT << PROXY_MAP_REPLY_SHIFT_BIT);
368 }
369
370 byteBuf.writeByte(msgType + proxyMapReply);
371
372 // fill zero into reserved field
373 byteBuf.writeByte((short) UNUSED_ZERO);
374
375 // want map notify flag
376 byte wantMapNotify = DISABLE_BIT;
377 if (message.isWantMapNotify()) {
378 wantMapNotify = (byte) ENABLE_BIT;
379 }
380
381 byteBuf.writeByte(wantMapNotify);
382
383 // record count
Jian Li42b3e432016-08-31 01:05:20 +0900384 byteBuf.writeByte(message.getMapRecords().size());
Jian Liedc5db12016-08-23 17:30:19 +0900385
386 // nonce
387 byteBuf.writeLong(message.getNonce());
388
389 // keyId
390 byteBuf.writeShort(message.getKeyId());
391
Jian Lif8c2d4a2016-09-15 02:33:12 +0900392 // authentication data and its length
Jian Lid1a109e2016-11-12 09:00:42 +0900393 if (message.getAuthData() == null) {
Jian Lif8c2d4a2016-09-15 02:33:12 +0900394 byteBuf.writeShort((short) 0);
395 } else {
Jian Lid1a109e2016-11-12 09:00:42 +0900396 byteBuf.writeShort(message.getAuthData().length);
397 byteBuf.writeBytes(message.getAuthData());
Jian Liedc5db12016-08-23 17:30:19 +0900398 }
399
Jian Liedc5db12016-08-23 17:30:19 +0900400 // serialize map records
Jian Lie4ba2a42016-08-29 20:24:15 +0900401 MapRecordWriter writer = new MapRecordWriter();
Jian Liedc5db12016-08-23 17:30:19 +0900402 List<LispMapRecord> records = message.getMapRecords();
403
404 for (int i = 0; i < records.size(); i++) {
405 writer.writeTo(byteBuf, records.get(i));
406 }
407 }
408 }
Jian Li451175e2016-07-19 23:22:20 +0900409}