blob: 5cb5877c09b126ab77e7c0e336fee18397a8dc72 [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 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 Li5e505c62016-12-05 02:44:24 +090026import org.onosproject.lisp.msg.authentication.LispAuthenticationFactory;
27import org.onosproject.lisp.msg.authentication.LispAuthenticationKeyEnum;
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 Li20850d32016-08-04 02:15:57 +090039
Jian Li451175e2016-07-19 23:22:20 +090040/**
41 * Default LISP map notify message class.
42 */
Jian Liafe2d3f2016-11-01 02:49:07 +090043public final class DefaultLispMapNotify extends AbstractLispMessage
44 implements LispMapNotify {
Jian Lif59c0ad2016-08-02 18:11:30 +090045
Jian Lid1a109e2016-11-12 09:00:42 +090046 private static final Logger log = LoggerFactory.getLogger(DefaultLispMapNotify.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
Yoonseon Hanca814bf2016-09-12 11:37:48 -070054 static final NotifyWriter WRITER;
Jian Lid1a109e2016-11-12 09:00:42 +090055
Yoonseon Hanca814bf2016-09-12 11:37:48 -070056 static {
57 WRITER = new NotifyWriter();
58 }
59
Jian Lif59c0ad2016-08-02 18:11:30 +090060 /**
61 * A private constructor that protects object instantiation from external.
62 *
Jian Lid1a109e2016-11-12 09:00:42 +090063 * @param nonce nonce
64 * @param keyId key identifier
65 * @param authData authentication data
66 * @param mapRecords a collection of map records
Jian Lif59c0ad2016-08-02 18:11:30 +090067 */
Jian Liedc5db12016-08-23 17:30:19 +090068 private DefaultLispMapNotify(long nonce, short keyId, short authDataLength,
Jian Lid1a109e2016-11-12 09:00:42 +090069 byte[] authData, List<LispMapRecord> mapRecords) {
Jian Lif59c0ad2016-08-02 18:11:30 +090070 this.nonce = nonce;
71 this.keyId = keyId;
Jian Liedc5db12016-08-23 17:30:19 +090072 this.authDataLength = authDataLength;
Jian Lid1a109e2016-11-12 09:00:42 +090073 this.authData = authData;
Jian Lif59c0ad2016-08-02 18:11:30 +090074 this.mapRecords = mapRecords;
75 }
Jian Li451175e2016-07-19 23:22:20 +090076
77 @Override
78 public LispType getType() {
Jian Lif59c0ad2016-08-02 18:11:30 +090079 return LispType.LISP_MAP_NOTIFY;
Jian Li451175e2016-07-19 23:22:20 +090080 }
81
82 @Override
Yoonseon Hanca814bf2016-09-12 11:37:48 -070083 public void writeTo(ByteBuf byteBuf) throws LispWriterException {
84 WRITER.writeTo(byteBuf, this);
Jian Li451175e2016-07-19 23:22:20 +090085 }
86
87 @Override
88 public Builder createBuilder() {
Jian Li525fded2016-08-04 01:15:33 +090089 return new DefaultNotifyBuilder();
Jian Li451175e2016-07-19 23:22:20 +090090 }
Jian Li719b3bf2016-07-22 00:38:29 +090091
92 @Override
93 public long getNonce() {
Jian Liedc5db12016-08-23 17:30:19 +090094 return nonce;
Jian Li719b3bf2016-07-22 00:38:29 +090095 }
96
97 @Override
Jian Li42b3e432016-08-31 01:05:20 +090098 public int getRecordCount() {
99 return mapRecords.size();
Jian Li719b3bf2016-07-22 00:38:29 +0900100 }
101
102 @Override
103 public short getKeyId() {
Jian Liedc5db12016-08-23 17:30:19 +0900104 return keyId;
105 }
106
107 @Override
108 public short getAuthDataLength() {
109 return authDataLength;
Jian Li719b3bf2016-07-22 00:38:29 +0900110 }
111
112 @Override
Jian Lid1a109e2016-11-12 09:00:42 +0900113 public byte[] getAuthData() {
114 if (authData != null && authData.length != 0) {
115 return ImmutableByteSequence.copyFrom(authData).asArray();
Jian Lie4ba2a42016-08-29 20:24:15 +0900116 } else {
117 return new byte[0];
118 }
Jian Li719b3bf2016-07-22 00:38:29 +0900119 }
120
121 @Override
Jian Liedc5db12016-08-23 17:30:19 +0900122 public List<LispMapRecord> getMapRecords() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900123 return ImmutableList.copyOf(mapRecords);
Jian Li719b3bf2016-07-22 00:38:29 +0900124 }
125
Jian Li20850d32016-08-04 02:15:57 +0900126 @Override
127 public String toString() {
128 return toStringHelper(this)
129 .add("type", getType())
130 .add("nonce", nonce)
Jian Li20850d32016-08-04 02:15:57 +0900131 .add("keyId", keyId)
Jian Liedc5db12016-08-23 17:30:19 +0900132 .add("authentication data length", authDataLength)
Jian Lid1a109e2016-11-12 09:00:42 +0900133 .add("authentication data", authData)
Jian Li20850d32016-08-04 02:15:57 +0900134 .add("mapRecords", mapRecords).toString();
135 }
136
137 @Override
138 public boolean equals(Object o) {
139 if (this == o) {
140 return true;
141 }
142 if (o == null || getClass() != o.getClass()) {
143 return false;
144 }
145 DefaultLispMapNotify that = (DefaultLispMapNotify) o;
146 return Objects.equal(nonce, that.nonce) &&
Jian Li20850d32016-08-04 02:15:57 +0900147 Objects.equal(keyId, that.keyId) &&
Jian Liedc5db12016-08-23 17:30:19 +0900148 Objects.equal(authDataLength, that.authDataLength) &&
Jian Lid1a109e2016-11-12 09:00:42 +0900149 Arrays.equals(authData, that.authData);
Jian Li20850d32016-08-04 02:15:57 +0900150 }
151
152 @Override
153 public int hashCode() {
Jian Li42b3e432016-08-31 01:05:20 +0900154 return Objects.hashCode(nonce, keyId, authDataLength) +
Jian Lid1a109e2016-11-12 09:00:42 +0900155 Arrays.hashCode(authData);
Jian Li20850d32016-08-04 02:15:57 +0900156 }
157
Jian Li719b3bf2016-07-22 00:38:29 +0900158 public static final class DefaultNotifyBuilder implements NotifyBuilder {
159
Jian Lif59c0ad2016-08-02 18:11:30 +0900160 private long nonce;
161 private short keyId;
Jian Liedc5db12016-08-23 17:30:19 +0900162 private short authDataLength;
Jian Lid1a109e2016-11-12 09:00:42 +0900163 private byte[] authData;
164 private String authKey;
Jian Lid4e63702016-08-30 18:29:20 +0900165 private List<LispMapRecord> mapRecords = Lists.newArrayList();
Jian Li719b3bf2016-07-22 00:38:29 +0900166
167 @Override
168 public LispType getType() {
Jian Lif59c0ad2016-08-02 18:11:30 +0900169 return LispType.LISP_MAP_NOTIFY;
Jian Li719b3bf2016-07-22 00:38:29 +0900170 }
171
172 @Override
173 public NotifyBuilder withNonce(long nonce) {
Jian Lif59c0ad2016-08-02 18:11:30 +0900174 this.nonce = nonce;
175 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900176 }
177
178 @Override
Jian Li719b3bf2016-07-22 00:38:29 +0900179 public NotifyBuilder withKeyId(short keyId) {
Jian Lif59c0ad2016-08-02 18:11:30 +0900180 this.keyId = keyId;
181 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900182 }
183
184 @Override
Jian Lid1a109e2016-11-12 09:00:42 +0900185 public NotifyBuilder withAuthKey(String key) {
186 this.authKey = key;
187 return this;
188 }
189
190 @Override
Jian Liedc5db12016-08-23 17:30:19 +0900191 public NotifyBuilder withAuthDataLength(short authDataLength) {
192 this.authDataLength = authDataLength;
193 return this;
194 }
195
196 @Override
Jian Lid1a109e2016-11-12 09:00:42 +0900197 public NotifyBuilder withAuthData(byte[] authData) {
198 if (authData != null) {
199 this.authData = authData;
Jian Lie4ba2a42016-08-29 20:24:15 +0900200 } else {
Jian Lid1a109e2016-11-12 09:00:42 +0900201 this.authData = new byte[0];
Jian Lie4ba2a42016-08-29 20:24:15 +0900202 }
Jian Lif59c0ad2016-08-02 18:11:30 +0900203 return this;
Jian Li719b3bf2016-07-22 00:38:29 +0900204 }
205
206 @Override
Jian Li47671902016-08-11 01:18:18 +0900207 public NotifyBuilder withMapRecords(List<LispMapRecord> mapRecords) {
Jian Lie4ba2a42016-08-29 20:24:15 +0900208 if (mapRecords != null) {
209 this.mapRecords = ImmutableList.copyOf(mapRecords);
Jian Lie4ba2a42016-08-29 20:24:15 +0900210 }
Jian Lif59c0ad2016-08-02 18:11:30 +0900211 return this;
212 }
213
214 @Override
Jian Li525fded2016-08-04 01:15:33 +0900215 public LispMapNotify build() {
Jian Lie4ba2a42016-08-29 20:24:15 +0900216
Jian Lid1a109e2016-11-12 09:00:42 +0900217 // if authentication data is not specified, we will calculate it
218 if (authData == null) {
219 LispAuthenticationFactory factory = LispAuthenticationFactory.getInstance();
220
221 authDataLength = LispAuthenticationKeyEnum.valueOf(keyId).getHashLength();
222 byte[] tmpAuthData = new byte[authDataLength];
223 Arrays.fill(tmpAuthData, (byte) 0);
224 authData = tmpAuthData;
225
226 ByteBuf byteBuf = Unpooled.buffer();
227 try {
228 new DefaultLispMapNotify(nonce, keyId, authDataLength,
229 authData, mapRecords).writeTo(byteBuf);
230 } catch (LispWriterException e) {
231 log.warn("Failed to serialize map notify message", e);
232 }
233
234 byte[] bytes = new byte[byteBuf.readableBytes()];
235 byteBuf.readBytes(bytes);
236
237 if (authKey == null) {
238 log.warn("Must specify authentication key");
239 }
240
241 authData = factory.createAuthenticationData(valueOf(keyId), authKey, bytes);
Jian Lie4ba2a42016-08-29 20:24:15 +0900242 }
243
Jian Lid1a109e2016-11-12 09:00:42 +0900244 return new DefaultLispMapNotify(nonce, keyId, authDataLength, authData, mapRecords);
Jian Li719b3bf2016-07-22 00:38:29 +0900245 }
246 }
Jian Li26069e22016-08-10 22:00:52 +0900247
248 /**
Jian Liedc5db12016-08-23 17:30:19 +0900249 * A LISP message reader for MapNotify message.
Jian Li26069e22016-08-10 22:00:52 +0900250 */
Jian Liedc5db12016-08-23 17:30:19 +0900251 public static final class NotifyReader implements LispMessageReader<LispMapNotify> {
Jian Li26069e22016-08-10 22:00:52 +0900252
Jian Li47671902016-08-11 01:18:18 +0900253 private static final int RESERVED_SKIP_LENGTH = 3;
254
Jian Li26069e22016-08-10 22:00:52 +0900255 @Override
Jian Lia7b394d2016-08-21 23:11:46 +0900256 public LispMapNotify readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException {
Jian Li47671902016-08-11 01:18:18 +0900257
258 if (byteBuf.readerIndex() != 0) {
259 return null;
260 }
261
262 // skip first three bytes as they represent type and reserved fields
263 byteBuf.skipBytes(RESERVED_SKIP_LENGTH);
264
265 // record count -> 8 bits
266 byte recordCount = (byte) byteBuf.readUnsignedByte();
267
268 // nonce -> 64 bits
269 long nonce = byteBuf.readLong();
270
271 // keyId -> 16 bits
272 short keyId = byteBuf.readShort();
273
274 // authenticationDataLength -> 16 bits
275 short authLength = byteBuf.readShort();
276
Jian Lid1a109e2016-11-12 09:00:42 +0900277 // authData -> depends on the authenticationDataLength
Jian Li47671902016-08-11 01:18:18 +0900278 byte[] authData = new byte[authLength];
279 byteBuf.readBytes(authData);
280
281 List<LispMapRecord> mapRecords = Lists.newArrayList();
282 for (int i = 0; i < recordCount; i++) {
Jian Li5e505c62016-12-05 02:44:24 +0900283 mapRecords.add(new MapRecordReader().readFrom(byteBuf));
Jian Li47671902016-08-11 01:18:18 +0900284 }
285
286 return new DefaultNotifyBuilder()
Jian Lid1a109e2016-11-12 09:00:42 +0900287 .withNonce(nonce)
288 .withKeyId(keyId)
289 .withAuthDataLength(authLength)
290 .withAuthData(authData)
291 .withMapRecords(mapRecords)
292 .build();
Jian Li26069e22016-08-10 22:00:52 +0900293 }
294 }
Jian Liedc5db12016-08-23 17:30:19 +0900295
296 /**
297 * A LISP message reader for MapNotify message.
298 */
299 public static final class NotifyWriter implements LispMessageWriter<LispMapNotify> {
300
Jian Liedc5db12016-08-23 17:30:19 +0900301 private static final int NOTIFY_SHIFT_BIT = 4;
302
303 private static final int UNUSED_ZERO = 0;
304
305 @Override
306 public void writeTo(ByteBuf byteBuf, LispMapNotify message) throws LispWriterException {
307
308 // specify LISP message type
Jian Licbc57e32016-09-14 09:06:54 +0900309 byte msgType = (byte) (LispType.LISP_MAP_NOTIFY.getTypeCode() << NOTIFY_SHIFT_BIT);
Jian Liedc5db12016-08-23 17:30:19 +0900310 byteBuf.writeByte(msgType);
311
312 // reserved field
313 byteBuf.writeShort((short) UNUSED_ZERO);
314
315 // record count
Jian Li42b3e432016-08-31 01:05:20 +0900316 byteBuf.writeByte(message.getMapRecords().size());
Jian Liedc5db12016-08-23 17:30:19 +0900317
318 // nonce
319 byteBuf.writeLong(message.getNonce());
320
321 // keyId
322 byteBuf.writeShort(message.getKeyId());
323
Jian Lif8c2d4a2016-09-15 02:33:12 +0900324 // authentication data and its length
Jian Lid1a109e2016-11-12 09:00:42 +0900325 if (message.getAuthData() == null) {
Jian Lif8c2d4a2016-09-15 02:33:12 +0900326 byteBuf.writeShort((short) 0);
327 } else {
Jian Lid1a109e2016-11-12 09:00:42 +0900328 byteBuf.writeShort(message.getAuthData().length);
329 byteBuf.writeBytes(message.getAuthData());
Jian Liedc5db12016-08-23 17:30:19 +0900330 }
331
Jian Liedc5db12016-08-23 17:30:19 +0900332 // serialize map records
333 MapRecordWriter writer = new MapRecordWriter();
334 List<LispMapRecord> records = message.getMapRecords();
335
336 for (int i = 0; i < records.size(); i++) {
337 writer.writeTo(byteBuf, records.get(i));
338 }
339 }
340 }
Jian Li451175e2016-07-19 23:22:20 +0900341}