blob: fff91857ca791c39406f26a354a012c6d7feda0c [file] [log] [blame]
Jian Li672ebda2017-02-06 20:21:04 +09001/*
2 * Copyright 2017-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
18import com.google.common.base.Objects;
19import com.google.common.collect.ImmutableList;
20import com.google.common.collect.Lists;
21import io.netty.buffer.ByteBuf;
22import org.onlab.packet.DeserializationException;
Jian Lid55111b2017-02-07 10:36:40 +090023import org.onlab.util.ByteOperator;
Jian Li672ebda2017-02-06 20:21:04 +090024import org.onosproject.lisp.msg.exceptions.LispParseError;
25import org.onosproject.lisp.msg.exceptions.LispReaderException;
26import org.onosproject.lisp.msg.exceptions.LispWriterException;
Jian Lid55111b2017-02-07 10:36:40 +090027import org.onosproject.lisp.msg.protocols.DefaultLispReferral.ReferralWriter;
Jian Li672ebda2017-02-06 20:21:04 +090028import org.onosproject.lisp.msg.types.LispAfiAddress;
Jian Lid55111b2017-02-07 10:36:40 +090029import org.onosproject.lisp.msg.types.LispAfiAddress.AfiAddressWriter;
Jian Li672ebda2017-02-06 20:21:04 +090030
31import java.util.List;
32
33import static com.google.common.base.MoreObjects.toStringHelper;
34import static com.google.common.base.Preconditions.checkNotNull;
35
36/**
37 * Default LISP referral record class.
38 */
39public final class DefaultLispReferralRecord extends AbstractLispRecord
40 implements LispReferralRecord {
41
42 private final boolean incomplete;
43 private final List<LispReferral> referrals;
44 private final List<LispSignature> signatures;
45
46 static final ReferralRecordWriter WRITER;
47 static {
48 WRITER = new ReferralRecordWriter();
49 }
50
51 /**
52 * A private constructor that protects object instantiation from external.
53 *
54 * @param recordTtl record time-to-live value
55 * @param maskLength mask length
56 * @param action lisp map reply action
57 * @param authoritative authoritative flag
58 * @param mapVersionNumber map version number
59 * @param eidPrefixAfi EID prefix AFI address
60 * @param incomplete incomplete flag value
61 * @param referrals a collection referrals
62 * @param signatures a collection signatures
63 */
64 private DefaultLispReferralRecord(int recordTtl, byte maskLength,
65 LispMapReplyAction action, boolean authoritative,
66 short mapVersionNumber, LispAfiAddress eidPrefixAfi,
67 boolean incomplete, List<LispReferral> referrals,
68 List<LispSignature> signatures) {
69 super(recordTtl, maskLength, action, authoritative, mapVersionNumber, eidPrefixAfi);
70 this.incomplete = incomplete;
71 this.referrals = referrals;
72 this.signatures = signatures;
73 }
74
75 @Override
76 public int getReferralCount() {
77 return referrals.size();
78 }
79
80 @Override
81 public int getSignatureCount() {
82 return signatures.size();
83 }
84
85 @Override
86 public boolean isIncomplete() {
87 return incomplete;
88 }
89
90 @Override
91 public List<LispReferral> getReferrals() {
92 return ImmutableList.copyOf(referrals);
93 }
94
95 @Override
96 public List<LispSignature> getSignatures() {
97 return ImmutableList.copyOf(signatures);
98 }
99
100 @Override
101 public void writeTo(ByteBuf byteBuf) throws LispWriterException {
102 WRITER.writeTo(byteBuf, this);
103 }
104
105 @Override
106 public String toString() {
107 return toStringHelper(this)
108 .add("record TTL", recordTtl)
109 .add("maskLength", maskLength)
110 .add("action", action)
111 .add("authoritative", authoritative)
112 .add("mapVersionNumber", mapVersionNumber)
113 .add("EID prefix AFI address", eidPrefixAfi)
114 .add("incomplete", incomplete)
115 .add("referrals", referrals)
116 .add("signatures", signatures)
117 .toString();
118 }
119
120 @Override
121 public boolean equals(Object o) {
122 if (this == o) {
123 return true;
124 }
125 if (o == null || getClass() != o.getClass()) {
126 return false;
127 }
128 DefaultLispReferralRecord that = (DefaultLispReferralRecord) o;
129 return Objects.equal(recordTtl, that.recordTtl) &&
130 Objects.equal(maskLength, that.maskLength) &&
131 Objects.equal(action, that.action) &&
132 Objects.equal(authoritative, that.authoritative) &&
133 Objects.equal(mapVersionNumber, that.mapVersionNumber) &&
134 Objects.equal(eidPrefixAfi, that.eidPrefixAfi) &&
135 Objects.equal(referrals, that.referrals) &&
136 Objects.equal(signatures, that.signatures);
137 }
138
139 @Override
140 public int hashCode() {
141 return Objects.hashCode(recordTtl, maskLength, action, authoritative,
142 mapVersionNumber, eidPrefixAfi, incomplete, referrals, signatures);
143 }
144
145 public static final class DefaultReferralRecordBuilder
146 extends AbstractRecordBuilder<ReferralRecordBuilder>
147 implements ReferralRecordBuilder {
148
149 private boolean incomplete;
150 private List<LispReferral> referrals = Lists.newArrayList();
151 private List<LispSignature> signatures = Lists.newArrayList();
152
153 @Override
154 public ReferralRecordBuilder withReferrals(List<LispReferral> referrals) {
155 if (referrals != null) {
156 this.referrals = ImmutableList.copyOf(referrals);
157 }
158 return this;
159 }
160
161 @Override
162 public ReferralRecordBuilder withSignatures(List<LispSignature> signatures) {
163 if (signatures != null) {
164 this.signatures = ImmutableList.copyOf(signatures);
165 }
166 return this;
167 }
168
169 @Override
170 public ReferralRecordBuilder withIsIncomplete(boolean incomplete) {
171 this.incomplete = incomplete;
172 return this;
173 }
174
175 @Override
176 public LispReferralRecord build() {
177
178 checkNotNull(eidPrefixAfi, "Must specify an EID prefix");
179
180 return new DefaultLispReferralRecord(recordTtl, maskLength, action,
181 authoritative, mapVersionNumber, eidPrefixAfi,
182 incomplete, referrals, signatures);
183 }
184 }
185
Jian Lid55111b2017-02-07 10:36:40 +0900186 /**
187 * A LISP message reader for ReferralRecord portion.
188 */
Jian Li672ebda2017-02-06 20:21:04 +0900189 public static final class ReferralRecordReader
190 implements LispMessageReader<LispReferralRecord> {
191
Jian Lid55111b2017-02-07 10:36:40 +0900192 private static final int INCOMPLETE_INDEX = 3;
193 private static final int AUTHORITATIVE_INDEX = 4;
194
195 private static final int REPLY_ACTION_SHIFT_BIT = 5;
196 private static final int RESERVED_SKIP_LENGTH = 1;
197
Jian Li672ebda2017-02-06 20:21:04 +0900198 @Override
199 public LispReferralRecord readFrom(ByteBuf byteBuf)
200 throws LispParseError, LispReaderException,
201 DeserializationException {
Jian Lid55111b2017-02-07 10:36:40 +0900202
203 // Record TTL -> 32 bits
204 int recordTtl = byteBuf.readInt();
205
206 // referral count -> 8 bits
207 int referralCount = byteBuf.readUnsignedByte();
208
209 // EID mask length -> 8 bits
210 byte maskLength = (byte) byteBuf.readUnsignedByte();
211
212 byte actionWithFlag = (byte) byteBuf.readUnsignedByte();
213
214 // action -> 3 bits
215 int actionByte = actionWithFlag >> REPLY_ACTION_SHIFT_BIT;
216 LispMapReplyAction action = LispMapReplyAction.valueOf(actionByte);
217 if (action == null) {
218 action = LispMapReplyAction.NoAction;
219 }
220
221 // authoritative flag -> 1 bit
222 boolean authoritative = ByteOperator.getBit((byte)
223 (actionWithFlag >> AUTHORITATIVE_INDEX), 0);
224
225 // incomplete flag -> 1 bit
226 boolean incomplete = ByteOperator.getBit((byte)
227 (actionWithFlag >> INCOMPLETE_INDEX), 0);
228
229 // let's skip the reserved field
230 byteBuf.skipBytes(RESERVED_SKIP_LENGTH);
231
232 // Map version number -> 12 bits, we treat Rsvd field is all zero
233 short mapVersionNumber = (short) byteBuf.readUnsignedShort();
234
235 LispAfiAddress eidPrefixAfi =
236 new LispAfiAddress.AfiAddressReader().readFrom(byteBuf);
237
238 List<LispReferral> referrals = Lists.newArrayList();
239 for (int i = 0; i < referralCount; i++) {
240 referrals.add(new DefaultLispReferral.ReferralReader().readFrom(byteBuf));
241 }
242
243 return new DefaultReferralRecordBuilder()
244 .withRecordTtl(recordTtl)
245 .withMaskLength(maskLength)
246 .withAction(action)
247 .withIsAuthoritative(authoritative)
248 .withIsIncomplete(incomplete)
249 .withMapVersionNumber(mapVersionNumber)
250 .withReferrals(referrals)
251 .withEidPrefixAfi(eidPrefixAfi)
252 .build();
Jian Li672ebda2017-02-06 20:21:04 +0900253 }
254 }
255
256 /**
257 * A LISP message writer for ReferralRecord portion.
258 */
259 public static final class ReferralRecordWriter
260 implements LispMessageWriter<LispReferralRecord> {
261
Jian Lid55111b2017-02-07 10:36:40 +0900262 private static final int REPLY_ACTION_SHIFT_BIT = 5;
263 private static final int INCOMPLETE_SHIFT_BIT = 3;
264 private static final int AUTHORITATIVE_SHIFT_BIT = 4;
265
266 private static final int ENABLE_BIT = 1;
267 private static final int DISABLE_BIT = 0;
268
269 private static final int UNUSED_ZERO = 0;
270
Jian Li672ebda2017-02-06 20:21:04 +0900271 @Override
272 public void writeTo(ByteBuf byteBuf, LispReferralRecord message)
273 throws LispWriterException {
Jian Lid55111b2017-02-07 10:36:40 +0900274 // record TTL
275 byteBuf.writeInt(message.getRecordTtl());
276
277 // referral count
278 byteBuf.writeByte((byte) message.getReferrals().size());
279
280 // EID mask length
281 byteBuf.writeByte(message.getMaskLength());
282
283 // reply action
284 byte action = (byte) (message.getAction().getAction() << REPLY_ACTION_SHIFT_BIT);
285
286 // authoritative bit
287 byte authoritative = DISABLE_BIT;
288 if (message.isAuthoritative()) {
289 authoritative = ENABLE_BIT << AUTHORITATIVE_SHIFT_BIT;
290 }
291
292 // incomplete bit
293 byte incomplete = DISABLE_BIT;
294 if (message.isIncomplete()) {
295 incomplete = ENABLE_BIT << INCOMPLETE_SHIFT_BIT;
296 }
297
298 byteBuf.writeByte((byte) (action + authoritative + incomplete));
299
300 // fill zero into reserved field
301 byteBuf.writeByte((short) UNUSED_ZERO);
302
303 // map version number
304 byteBuf.writeShort(message.getMapVersionNumber());
305
306 // EID prefix AFI with EID prefix
307 AfiAddressWriter afiAddressWriter = new AfiAddressWriter();
308 afiAddressWriter.writeTo(byteBuf, message.getEidPrefixAfi());
309
310 // serialize referrals
311 ReferralWriter referralWriter = new ReferralWriter();
312 List<LispReferral> referrals = message.getReferrals();
313 for (int i = 0; i < referrals.size(); i++) {
314 referralWriter.writeTo(byteBuf, referrals.get(i));
315 }
Jian Li672ebda2017-02-06 20:21:04 +0900316 }
317 }
318}