blob: fff91857ca791c39406f26a354a012c6d7feda0c [file] [log] [blame]
/*
* Copyright 2017-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.lisp.msg.protocols;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import io.netty.buffer.ByteBuf;
import org.onlab.packet.DeserializationException;
import org.onlab.util.ByteOperator;
import org.onosproject.lisp.msg.exceptions.LispParseError;
import org.onosproject.lisp.msg.exceptions.LispReaderException;
import org.onosproject.lisp.msg.exceptions.LispWriterException;
import org.onosproject.lisp.msg.protocols.DefaultLispReferral.ReferralWriter;
import org.onosproject.lisp.msg.types.LispAfiAddress;
import org.onosproject.lisp.msg.types.LispAfiAddress.AfiAddressWriter;
import java.util.List;
import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Default LISP referral record class.
*/
public final class DefaultLispReferralRecord extends AbstractLispRecord
implements LispReferralRecord {
private final boolean incomplete;
private final List<LispReferral> referrals;
private final List<LispSignature> signatures;
static final ReferralRecordWriter WRITER;
static {
WRITER = new ReferralRecordWriter();
}
/**
* A private constructor that protects object instantiation from external.
*
* @param recordTtl record time-to-live value
* @param maskLength mask length
* @param action lisp map reply action
* @param authoritative authoritative flag
* @param mapVersionNumber map version number
* @param eidPrefixAfi EID prefix AFI address
* @param incomplete incomplete flag value
* @param referrals a collection referrals
* @param signatures a collection signatures
*/
private DefaultLispReferralRecord(int recordTtl, byte maskLength,
LispMapReplyAction action, boolean authoritative,
short mapVersionNumber, LispAfiAddress eidPrefixAfi,
boolean incomplete, List<LispReferral> referrals,
List<LispSignature> signatures) {
super(recordTtl, maskLength, action, authoritative, mapVersionNumber, eidPrefixAfi);
this.incomplete = incomplete;
this.referrals = referrals;
this.signatures = signatures;
}
@Override
public int getReferralCount() {
return referrals.size();
}
@Override
public int getSignatureCount() {
return signatures.size();
}
@Override
public boolean isIncomplete() {
return incomplete;
}
@Override
public List<LispReferral> getReferrals() {
return ImmutableList.copyOf(referrals);
}
@Override
public List<LispSignature> getSignatures() {
return ImmutableList.copyOf(signatures);
}
@Override
public void writeTo(ByteBuf byteBuf) throws LispWriterException {
WRITER.writeTo(byteBuf, this);
}
@Override
public String toString() {
return toStringHelper(this)
.add("record TTL", recordTtl)
.add("maskLength", maskLength)
.add("action", action)
.add("authoritative", authoritative)
.add("mapVersionNumber", mapVersionNumber)
.add("EID prefix AFI address", eidPrefixAfi)
.add("incomplete", incomplete)
.add("referrals", referrals)
.add("signatures", signatures)
.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DefaultLispReferralRecord that = (DefaultLispReferralRecord) o;
return Objects.equal(recordTtl, that.recordTtl) &&
Objects.equal(maskLength, that.maskLength) &&
Objects.equal(action, that.action) &&
Objects.equal(authoritative, that.authoritative) &&
Objects.equal(mapVersionNumber, that.mapVersionNumber) &&
Objects.equal(eidPrefixAfi, that.eidPrefixAfi) &&
Objects.equal(referrals, that.referrals) &&
Objects.equal(signatures, that.signatures);
}
@Override
public int hashCode() {
return Objects.hashCode(recordTtl, maskLength, action, authoritative,
mapVersionNumber, eidPrefixAfi, incomplete, referrals, signatures);
}
public static final class DefaultReferralRecordBuilder
extends AbstractRecordBuilder<ReferralRecordBuilder>
implements ReferralRecordBuilder {
private boolean incomplete;
private List<LispReferral> referrals = Lists.newArrayList();
private List<LispSignature> signatures = Lists.newArrayList();
@Override
public ReferralRecordBuilder withReferrals(List<LispReferral> referrals) {
if (referrals != null) {
this.referrals = ImmutableList.copyOf(referrals);
}
return this;
}
@Override
public ReferralRecordBuilder withSignatures(List<LispSignature> signatures) {
if (signatures != null) {
this.signatures = ImmutableList.copyOf(signatures);
}
return this;
}
@Override
public ReferralRecordBuilder withIsIncomplete(boolean incomplete) {
this.incomplete = incomplete;
return this;
}
@Override
public LispReferralRecord build() {
checkNotNull(eidPrefixAfi, "Must specify an EID prefix");
return new DefaultLispReferralRecord(recordTtl, maskLength, action,
authoritative, mapVersionNumber, eidPrefixAfi,
incomplete, referrals, signatures);
}
}
/**
* A LISP message reader for ReferralRecord portion.
*/
public static final class ReferralRecordReader
implements LispMessageReader<LispReferralRecord> {
private static final int INCOMPLETE_INDEX = 3;
private static final int AUTHORITATIVE_INDEX = 4;
private static final int REPLY_ACTION_SHIFT_BIT = 5;
private static final int RESERVED_SKIP_LENGTH = 1;
@Override
public LispReferralRecord readFrom(ByteBuf byteBuf)
throws LispParseError, LispReaderException,
DeserializationException {
// Record TTL -> 32 bits
int recordTtl = byteBuf.readInt();
// referral count -> 8 bits
int referralCount = byteBuf.readUnsignedByte();
// EID mask length -> 8 bits
byte maskLength = (byte) byteBuf.readUnsignedByte();
byte actionWithFlag = (byte) byteBuf.readUnsignedByte();
// action -> 3 bits
int actionByte = actionWithFlag >> REPLY_ACTION_SHIFT_BIT;
LispMapReplyAction action = LispMapReplyAction.valueOf(actionByte);
if (action == null) {
action = LispMapReplyAction.NoAction;
}
// authoritative flag -> 1 bit
boolean authoritative = ByteOperator.getBit((byte)
(actionWithFlag >> AUTHORITATIVE_INDEX), 0);
// incomplete flag -> 1 bit
boolean incomplete = ByteOperator.getBit((byte)
(actionWithFlag >> INCOMPLETE_INDEX), 0);
// let's skip the reserved field
byteBuf.skipBytes(RESERVED_SKIP_LENGTH);
// Map version number -> 12 bits, we treat Rsvd field is all zero
short mapVersionNumber = (short) byteBuf.readUnsignedShort();
LispAfiAddress eidPrefixAfi =
new LispAfiAddress.AfiAddressReader().readFrom(byteBuf);
List<LispReferral> referrals = Lists.newArrayList();
for (int i = 0; i < referralCount; i++) {
referrals.add(new DefaultLispReferral.ReferralReader().readFrom(byteBuf));
}
return new DefaultReferralRecordBuilder()
.withRecordTtl(recordTtl)
.withMaskLength(maskLength)
.withAction(action)
.withIsAuthoritative(authoritative)
.withIsIncomplete(incomplete)
.withMapVersionNumber(mapVersionNumber)
.withReferrals(referrals)
.withEidPrefixAfi(eidPrefixAfi)
.build();
}
}
/**
* A LISP message writer for ReferralRecord portion.
*/
public static final class ReferralRecordWriter
implements LispMessageWriter<LispReferralRecord> {
private static final int REPLY_ACTION_SHIFT_BIT = 5;
private static final int INCOMPLETE_SHIFT_BIT = 3;
private static final int AUTHORITATIVE_SHIFT_BIT = 4;
private static final int ENABLE_BIT = 1;
private static final int DISABLE_BIT = 0;
private static final int UNUSED_ZERO = 0;
@Override
public void writeTo(ByteBuf byteBuf, LispReferralRecord message)
throws LispWriterException {
// record TTL
byteBuf.writeInt(message.getRecordTtl());
// referral count
byteBuf.writeByte((byte) message.getReferrals().size());
// EID mask length
byteBuf.writeByte(message.getMaskLength());
// reply action
byte action = (byte) (message.getAction().getAction() << REPLY_ACTION_SHIFT_BIT);
// authoritative bit
byte authoritative = DISABLE_BIT;
if (message.isAuthoritative()) {
authoritative = ENABLE_BIT << AUTHORITATIVE_SHIFT_BIT;
}
// incomplete bit
byte incomplete = DISABLE_BIT;
if (message.isIncomplete()) {
incomplete = ENABLE_BIT << INCOMPLETE_SHIFT_BIT;
}
byteBuf.writeByte((byte) (action + authoritative + incomplete));
// fill zero into reserved field
byteBuf.writeByte((short) UNUSED_ZERO);
// map version number
byteBuf.writeShort(message.getMapVersionNumber());
// EID prefix AFI with EID prefix
AfiAddressWriter afiAddressWriter = new AfiAddressWriter();
afiAddressWriter.writeTo(byteBuf, message.getEidPrefixAfi());
// serialize referrals
ReferralWriter referralWriter = new ReferralWriter();
List<LispReferral> referrals = message.getReferrals();
for (int i = 0; i < referrals.size(); i++) {
referralWriter.writeTo(byteBuf, referrals.get(i));
}
}
}
}