blob: d6a27fbdfc725798a4d22c2124901e67f54ead2f [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 Lif59c0ad2016-08-02 18:11:30 +090023import org.onlab.util.ImmutableByteSequence;
Jian Lid1a109e2016-11-12 09:00:42 +090024import org.onosproject.lisp.msg.authentication.LispAuthenticationFactory;
25import org.onosproject.lisp.msg.authentication.LispAuthenticationKeyEnum;
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 Lid1a109e2016-11-12 09:00:42 +090029import org.slf4j.Logger;
30import org.slf4j.LoggerFactory;
Jian Li451175e2016-07-19 23:22:20 +090031
Jian Liedc5db12016-08-23 17:30:19 +090032import java.util.Arrays;
Jian Li719b3bf2016-07-22 00:38:29 +090033import java.util.List;
34
Jian Li20850d32016-08-04 02:15:57 +090035import static com.google.common.base.MoreObjects.toStringHelper;
Jian Lid1a109e2016-11-12 09:00:42 +090036import static org.onosproject.lisp.msg.authentication.LispAuthenticationKeyEnum.valueOf;
Jian Liedc5db12016-08-23 17:30:19 +090037import static org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.MapRecordWriter;
Jian Li20850d32016-08-04 02:15:57 +090038
Jian Li451175e2016-07-19 23:22:20 +090039/**
40 * Default LISP map notify message class.
41 */
Jian Liafe2d3f2016-11-01 02:49:07 +090042public final class DefaultLispMapNotify extends AbstractLispMessage
43 implements LispMapNotify {
Jian Lif59c0ad2016-08-02 18:11:30 +090044
Jian Lid1a109e2016-11-12 09:00:42 +090045 private static final Logger log = LoggerFactory.getLogger(DefaultLispMapNotify.class);
46
Jian Lif59c0ad2016-08-02 18:11:30 +090047 private final long nonce;
48 private final short keyId;
Jian Liedc5db12016-08-23 17:30:19 +090049 private final short authDataLength;
Jian Lid1a109e2016-11-12 09:00:42 +090050 private final byte[] authData;
Jian Lif59c0ad2016-08-02 18:11:30 +090051 private final List<LispMapRecord> mapRecords;
52
Yoonseon Hanca814bf2016-09-12 11:37:48 -070053 static final NotifyWriter WRITER;
Jian Lid1a109e2016-11-12 09:00:42 +090054
Yoonseon Hanca814bf2016-09-12 11:37:48 -070055 static {
56 WRITER = new NotifyWriter();
57 }
58
Jian Lif59c0ad2016-08-02 18:11:30 +090059 /**
60 * A private constructor that protects object instantiation from external.
61 *
Jian Lid1a109e2016-11-12 09:00:42 +090062 * @param nonce nonce
63 * @param keyId key identifier
64 * @param authData authentication data
65 * @param mapRecords a collection of map records
Jian Lif59c0ad2016-08-02 18:11:30 +090066 */
Jian Liedc5db12016-08-23 17:30:19 +090067 private DefaultLispMapNotify(long nonce, short keyId, short authDataLength,
Jian Lid1a109e2016-11-12 09:00:42 +090068 byte[] authData, List<LispMapRecord> mapRecords) {
Jian Lif59c0ad2016-08-02 18:11:30 +090069 this.nonce = nonce;
70 this.keyId = keyId;
Jian Liedc5db12016-08-23 17:30:19 +090071 this.authDataLength = authDataLength;
Jian Lid1a109e2016-11-12 09:00:42 +090072 this.authData = authData;
Jian Lif59c0ad2016-08-02 18:11:30 +090073 this.mapRecords = mapRecords;
74 }
Jian Li451175e2016-07-19 23:22:20 +090075
76 @Override
77 public LispType getType() {
Jian Lif59c0ad2016-08-02 18:11:30 +090078 return LispType.LISP_MAP_NOTIFY;
Jian Li451175e2016-07-19 23:22:20 +090079 }
80
81 @Override
Yoonseon Hanca814bf2016-09-12 11:37:48 -070082 public void writeTo(ByteBuf byteBuf) throws LispWriterException {
83 WRITER.writeTo(byteBuf, this);
Jian Li451175e2016-07-19 23:22:20 +090084 }
85
86 @Override
87 public Builder createBuilder() {
Jian Li525fded2016-08-04 01:15:33 +090088 return new DefaultNotifyBuilder();
Jian Li451175e2016-07-19 23:22:20 +090089 }
Jian Li719b3bf2016-07-22 00:38:29 +090090
91 @Override
92 public long getNonce() {
Jian Liedc5db12016-08-23 17:30:19 +090093 return nonce;
Jian Li719b3bf2016-07-22 00:38:29 +090094 }
95
96 @Override
Jian Li42b3e432016-08-31 01:05:20 +090097 public int getRecordCount() {
98 return mapRecords.size();
Jian Li719b3bf2016-07-22 00:38:29 +090099 }
100
101 @Override
102 public short getKeyId() {
Jian Liedc5db12016-08-23 17:30:19 +0900103 return keyId;
104 }
105
106 @Override
107 public short getAuthDataLength() {
108 return authDataLength;
Jian Li719b3bf2016-07-22 00:38:29 +0900109 }
110
111 @Override
Jian Lid1a109e2016-11-12 09:00:42 +0900112 public byte[] getAuthData() {
113 if (authData != null && authData.length != 0) {
114 return ImmutableByteSequence.copyFrom(authData).asArray();
Jian Lie4ba2a42016-08-29 20:24:15 +0900115 } else {
116 return new byte[0];
117 }
Jian Li719b3bf2016-07-22 00:38:29 +0900118 }
119
120 @Override
Jian Liedc5db12016-08-23 17:30:19 +0900121 public List<LispMapRecord> getMapRecords() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900122 return ImmutableList.copyOf(mapRecords);
Jian Li719b3bf2016-07-22 00:38:29 +0900123 }
124
Jian Li20850d32016-08-04 02:15:57 +0900125 @Override
126 public String toString() {
127 return toStringHelper(this)
128 .add("type", getType())
129 .add("nonce", nonce)
Jian Li20850d32016-08-04 02:15:57 +0900130 .add("keyId", keyId)
Jian Liedc5db12016-08-23 17:30:19 +0900131 .add("authentication data length", authDataLength)
Jian Lid1a109e2016-11-12 09:00:42 +0900132 .add("authentication data", authData)
Jian Li20850d32016-08-04 02:15:57 +0900133 .add("mapRecords", mapRecords).toString();
134 }
135
136 @Override
137 public boolean equals(Object o) {
138 if (this == o) {
139 return true;
140 }
141 if (o == null || getClass() != o.getClass()) {
142 return false;
143 }
144 DefaultLispMapNotify that = (DefaultLispMapNotify) o;
145 return Objects.equal(nonce, that.nonce) &&
Jian Li20850d32016-08-04 02:15:57 +0900146 Objects.equal(keyId, that.keyId) &&
Jian Liedc5db12016-08-23 17:30:19 +0900147 Objects.equal(authDataLength, that.authDataLength) &&
Jian Lid1a109e2016-11-12 09:00:42 +0900148 Arrays.equals(authData, that.authData);
Jian Li20850d32016-08-04 02:15:57 +0900149 }
150
151 @Override
152 public int hashCode() {
Jian Li42b3e432016-08-31 01:05:20 +0900153 return Objects.hashCode(nonce, keyId, authDataLength) +
Jian Lid1a109e2016-11-12 09:00:42 +0900154 Arrays.hashCode(authData);
Jian Li20850d32016-08-04 02:15:57 +0900155 }
156
Jian Li719b3bf2016-07-22 00:38:29 +0900157 public static final class DefaultNotifyBuilder implements NotifyBuilder {
158
Jian Lif59c0ad2016-08-02 18:11:30 +0900159 private long nonce;
160 private short keyId;
Jian Liedc5db12016-08-23 17:30:19 +0900161 private short authDataLength;
Jian Lid1a109e2016-11-12 09:00:42 +0900162 private byte[] authData;
163 private String authKey;
Jian Lid4e63702016-08-30 18:29:20 +0900164 private List<LispMapRecord> mapRecords = Lists.newArrayList();
Jian Li719b3bf2016-07-22 00:38:29 +0900165
166 @Override
167 public LispType getType() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900168 return LispType.LISP_MAP_NOTIFY;
Jian Li719b3bf2016-07-22 00:38:29 +0900169 }
170
171 @Override
172 public NotifyBuilder withNonce(long nonce) {
Jian Lif59c0ad2016-08-02 18:11:30 +0900173 this.nonce = nonce;
174 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900175 }
176
177 @Override
Jian Li719b3bf2016-07-22 00:38:29 +0900178 public NotifyBuilder withKeyId(short keyId) {
Jian Lif59c0ad2016-08-02 18:11:30 +0900179 this.keyId = keyId;
180 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900181 }
182
183 @Override
Jian Lid1a109e2016-11-12 09:00:42 +0900184 public NotifyBuilder withAuthKey(String key) {
185 this.authKey = key;
186 return this;
187 }
188
189 @Override
Jian Liedc5db12016-08-23 17:30:19 +0900190 public NotifyBuilder withAuthDataLength(short authDataLength) {
191 this.authDataLength = authDataLength;
192 return this;
193 }
194
195 @Override
Jian Lid1a109e2016-11-12 09:00:42 +0900196 public NotifyBuilder withAuthData(byte[] authData) {
197 if (authData != null) {
198 this.authData = authData;
Jian Lie4ba2a42016-08-29 20:24:15 +0900199 } else {
Jian Lid1a109e2016-11-12 09:00:42 +0900200 this.authData = new byte[0];
Jian Lie4ba2a42016-08-29 20:24:15 +0900201 }
Jian Lif59c0ad2016-08-02 18:11:30 +0900202 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900203 }
204
205 @Override
Jian Li47671902016-08-11 01:18:18 +0900206 public NotifyBuilder withMapRecords(List<LispMapRecord> mapRecords) {
Jian Lie4ba2a42016-08-29 20:24:15 +0900207 if (mapRecords != null) {
208 this.mapRecords = ImmutableList.copyOf(mapRecords);
Jian Lie4ba2a42016-08-29 20:24:15 +0900209 }
Jian Lif59c0ad2016-08-02 18:11:30 +0900210 return this;
211 }
212
213 @Override
Jian Li525fded2016-08-04 01:15:33 +0900214 public LispMapNotify build() {
Jian Lie4ba2a42016-08-29 20:24:15 +0900215
Jian Lid1a109e2016-11-12 09:00:42 +0900216 // if authentication data is not specified, we will calculate it
217 if (authData == null) {
218 LispAuthenticationFactory factory = LispAuthenticationFactory.getInstance();
219
220 authDataLength = LispAuthenticationKeyEnum.valueOf(keyId).getHashLength();
221 byte[] tmpAuthData = new byte[authDataLength];
222 Arrays.fill(tmpAuthData, (byte) 0);
223 authData = tmpAuthData;
224
225 ByteBuf byteBuf = Unpooled.buffer();
226 try {
227 new DefaultLispMapNotify(nonce, keyId, authDataLength,
228 authData, mapRecords).writeTo(byteBuf);
229 } catch (LispWriterException e) {
230 log.warn("Failed to serialize map notify message", e);
231 }
232
233 byte[] bytes = new byte[byteBuf.readableBytes()];
234 byteBuf.readBytes(bytes);
235
236 if (authKey == null) {
237 log.warn("Must specify authentication key");
238 }
239
240 authData = factory.createAuthenticationData(valueOf(keyId), authKey, bytes);
Jian Lie4ba2a42016-08-29 20:24:15 +0900241 }
242
Jian Lid1a109e2016-11-12 09:00:42 +0900243 return new DefaultLispMapNotify(nonce, keyId, authDataLength, authData, mapRecords);
Jian Li719b3bf2016-07-22 00:38:29 +0900244 }
245 }
Jian Li26069e22016-08-10 22:00:52 +0900246
247 /**
Jian Liedc5db12016-08-23 17:30:19 +0900248 * A LISP message reader for MapNotify message.
Jian Li26069e22016-08-10 22:00:52 +0900249 */
Jian Liedc5db12016-08-23 17:30:19 +0900250 public static final class NotifyReader implements LispMessageReader<LispMapNotify> {
Jian Li26069e22016-08-10 22:00:52 +0900251
Jian Li47671902016-08-11 01:18:18 +0900252 private static final int RESERVED_SKIP_LENGTH = 3;
253
Jian Li26069e22016-08-10 22:00:52 +0900254 @Override
Jian Lia7b394d2016-08-21 23:11:46 +0900255 public LispMapNotify readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException {
Jian Li47671902016-08-11 01:18:18 +0900256
257 if (byteBuf.readerIndex() != 0) {
258 return null;
259 }
260
261 // skip first three bytes as they represent type and reserved fields
262 byteBuf.skipBytes(RESERVED_SKIP_LENGTH);
263
264 // record count -> 8 bits
265 byte recordCount = (byte) byteBuf.readUnsignedByte();
266
267 // nonce -> 64 bits
268 long nonce = byteBuf.readLong();
269
270 // keyId -> 16 bits
271 short keyId = byteBuf.readShort();
272
273 // authenticationDataLength -> 16 bits
274 short authLength = byteBuf.readShort();
275
Jian Lid1a109e2016-11-12 09:00:42 +0900276 // authData -> depends on the authenticationDataLength
Jian Li47671902016-08-11 01:18:18 +0900277 byte[] authData = new byte[authLength];
278 byteBuf.readBytes(authData);
279
280 List<LispMapRecord> mapRecords = Lists.newArrayList();
281 for (int i = 0; i < recordCount; i++) {
282 mapRecords.add(new DefaultLispMapRecord.MapRecordReader().readFrom(byteBuf));
283 }
284
285 return new DefaultNotifyBuilder()
Jian Lid1a109e2016-11-12 09:00:42 +0900286 .withNonce(nonce)
287 .withKeyId(keyId)
288 .withAuthDataLength(authLength)
289 .withAuthData(authData)
290 .withMapRecords(mapRecords)
291 .build();
Jian Li26069e22016-08-10 22:00:52 +0900292 }
293 }
Jian Liedc5db12016-08-23 17:30:19 +0900294
295 /**
296 * A LISP message reader for MapNotify message.
297 */
298 public static final class NotifyWriter implements LispMessageWriter<LispMapNotify> {
299
Jian Liedc5db12016-08-23 17:30:19 +0900300 private static final int NOTIFY_SHIFT_BIT = 4;
301
302 private static final int UNUSED_ZERO = 0;
303
304 @Override
305 public void writeTo(ByteBuf byteBuf, LispMapNotify message) throws LispWriterException {
306
307 // specify LISP message type
Jian Licbc57e32016-09-14 09:06:54 +0900308 byte msgType = (byte) (LispType.LISP_MAP_NOTIFY.getTypeCode() << NOTIFY_SHIFT_BIT);
Jian Liedc5db12016-08-23 17:30:19 +0900309 byteBuf.writeByte(msgType);
310
311 // reserved field
312 byteBuf.writeShort((short) UNUSED_ZERO);
313
314 // record count
Jian Li42b3e432016-08-31 01:05:20 +0900315 byteBuf.writeByte(message.getMapRecords().size());
Jian Liedc5db12016-08-23 17:30:19 +0900316
317 // nonce
318 byteBuf.writeLong(message.getNonce());
319
320 // keyId
321 byteBuf.writeShort(message.getKeyId());
322
Jian Lif8c2d4a2016-09-15 02:33:12 +0900323 // authentication data and its length
Jian Lid1a109e2016-11-12 09:00:42 +0900324 if (message.getAuthData() == null) {
Jian Lif8c2d4a2016-09-15 02:33:12 +0900325 byteBuf.writeShort((short) 0);
326 } else {
Jian Lid1a109e2016-11-12 09:00:42 +0900327 byteBuf.writeShort(message.getAuthData().length);
328 byteBuf.writeBytes(message.getAuthData());
Jian Liedc5db12016-08-23 17:30:19 +0900329 }
330
Jian Liedc5db12016-08-23 17:30:19 +0900331 // serialize map records
332 MapRecordWriter writer = new MapRecordWriter();
333 List<LispMapRecord> records = message.getMapRecords();
334
335 for (int i = 0; i < records.size(); i++) {
336 writer.writeTo(byteBuf, records.get(i));
337 }
338 }
339 }
Jian Li451175e2016-07-19 23:22:20 +0900340}