blob: c44c909b956f30d9597cf89ff45e5ef678f57fcc [file] [log] [blame]
/*
* Copyright 2016-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.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.types.LispAfiAddress;
import java.util.List;
import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.lisp.msg.types.LispAfiAddress.AfiAddressWriter;
import static org.onosproject.lisp.msg.protocols.LispEidRecord.EidRecordWriter;
/**
* Default LISP map request message class.
*/
public final class DefaultLispMapRequest implements LispMapRequest {
private final long nonce;
private final byte recordCount;
private final LispAfiAddress sourceEid;
private final List<LispAfiAddress> itrRlocs;
private final List<LispEidRecord> eidRecords;
private final boolean authoritative;
private final boolean mapDataPresent;
private final boolean probe;
private final boolean smr;
private final boolean pitr;
private final boolean smrInvoked;
/**
* A private constructor that protects object instantiation from external.
*
* @param nonce nonce
* @param recordCount record count number
* @param sourceEid source EID address
* @param itrRlocs a collection of ITR RLOCs
* @param eidRecords a collection of EID records
* @param authoritative authoritative flag
* @param mapDataPresent map data present flag
* @param probe probe flag
* @param smr smr flag
* @param pitr pitr flag
* @param smrInvoked smrInvoked flag
*/
private DefaultLispMapRequest(long nonce, byte recordCount, LispAfiAddress sourceEid,
List<LispAfiAddress> itrRlocs, List<LispEidRecord> eidRecords,
boolean authoritative, boolean mapDataPresent, boolean probe,
boolean smr, boolean pitr, boolean smrInvoked) {
this.nonce = nonce;
this.recordCount = recordCount;
this.sourceEid = sourceEid;
this.itrRlocs = itrRlocs;
this.eidRecords = eidRecords;
this.authoritative = authoritative;
this.mapDataPresent = mapDataPresent;
this.probe = probe;
this.smr = smr;
this.pitr = pitr;
this.smrInvoked = smrInvoked;
}
@Override
public LispType getType() {
return LispType.LISP_MAP_REQUEST;
}
@Override
public void writeTo(ByteBuf byteBuf) {
// TODO: serialize LispMapRequest message
}
@Override
public Builder createBuilder() {
return new DefaultRequestBuilder();
}
@Override
public boolean isAuthoritative() {
return authoritative;
}
@Override
public boolean isMapDataPresent() {
return mapDataPresent;
}
@Override
public boolean isProbe() {
return probe;
}
@Override
public boolean isSmr() {
return smr;
}
@Override
public boolean isPitr() {
return pitr;
}
@Override
public boolean isSmrInvoked() {
return smrInvoked;
}
@Override
public byte getRecordCount() {
return recordCount;
}
@Override
public long getNonce() {
return nonce;
}
@Override
public LispAfiAddress getSourceEid() {
return sourceEid;
}
@Override
public List<LispAfiAddress> getItrRlocs() {
return ImmutableList.copyOf(itrRlocs);
}
@Override
public List<LispEidRecord> getEids() {
return ImmutableList.copyOf(eidRecords);
}
@Override
public String toString() {
return toStringHelper(this)
.add("type", getType())
.add("nonce", nonce)
.add("recordCount", recordCount)
.add("source EID", sourceEid)
.add("ITR rlocs", itrRlocs)
.add("EID records", eidRecords)
.add("authoritative", authoritative)
.add("mapDataPresent", mapDataPresent)
.add("probe", probe)
.add("SMR", smr)
.add("Proxy ITR", pitr)
.add("SMR Invoked", smrInvoked).toString();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DefaultLispMapRequest that = (DefaultLispMapRequest) o;
return Objects.equal(nonce, that.nonce) &&
Objects.equal(recordCount, that.recordCount) &&
Objects.equal(sourceEid, that.sourceEid) &&
Objects.equal(authoritative, that.authoritative) &&
Objects.equal(mapDataPresent, that.mapDataPresent) &&
Objects.equal(probe, that.probe) &&
Objects.equal(smr, that.smr) &&
Objects.equal(pitr, that.pitr) &&
Objects.equal(smrInvoked, that.smrInvoked);
}
@Override
public int hashCode() {
return Objects.hashCode(nonce, recordCount, sourceEid, authoritative,
mapDataPresent, probe, smr, pitr, smrInvoked);
}
public static final class DefaultRequestBuilder implements RequestBuilder {
private long nonce;
private byte recordCount;
private LispAfiAddress sourceEid;
private List<LispAfiAddress> itrRlocs = Lists.newArrayList();
private List<LispEidRecord> eidRecords = Lists.newArrayList();
private boolean authoritative;
private boolean mapDataPresent;
private boolean probe;
private boolean smr;
private boolean pitr;
private boolean smrInvoked;
@Override
public LispType getType() {
return LispType.LISP_MAP_REQUEST;
}
@Override
public RequestBuilder withIsAuthoritative(boolean authoritative) {
this.authoritative = authoritative;
return this;
}
@Override
public RequestBuilder withIsProbe(boolean probe) {
this.probe = probe;
return this;
}
@Override
public RequestBuilder withIsMapDataPresent(boolean mapDataPresent) {
this.mapDataPresent = mapDataPresent;
return this;
}
@Override
public RequestBuilder withIsSmr(boolean smr) {
this.smr = smr;
return this;
}
@Override
public RequestBuilder withIsPitr(boolean pitr) {
this.pitr = pitr;
return this;
}
@Override
public RequestBuilder withIsSmrInvoked(boolean smrInvoked) {
this.smrInvoked = smrInvoked;
return this;
}
@Override
public RequestBuilder withRecordCount(byte recordCount) {
this.recordCount = recordCount;
return this;
}
@Override
public RequestBuilder withNonce(long nonce) {
this.nonce = nonce;
return this;
}
@Override
public RequestBuilder withSourceEid(LispAfiAddress sourceEid) {
this.sourceEid = sourceEid;
return this;
}
@Override
public RequestBuilder withItrRlocs(List<LispAfiAddress> itrRlocs) {
if (itrRlocs != null) {
this.itrRlocs = ImmutableList.copyOf(itrRlocs);
}
return this;
}
@Override
public RequestBuilder withEidRecords(List<LispEidRecord> records) {
if (records != null) {
this.eidRecords = ImmutableList.copyOf(records);
}
return this;
}
@Override
public LispMapRequest build() {
checkNotNull(sourceEid, "Must have a source EID");
checkArgument((itrRlocs != null) && (itrRlocs.size() > 0), "Must have an ITR RLOC entry");
return new DefaultLispMapRequest(nonce, recordCount, sourceEid, itrRlocs,
eidRecords, authoritative, mapDataPresent, probe, smr, pitr, smrInvoked);
}
}
/**
* A LISP message reader for MapRequest message.
*/
public static final class RequestReader implements LispMessageReader<LispMapRequest> {
private static final int AUTHORITATIVE_INDEX = 3;
private static final int MAP_DATA_PRESENT_INDEX = 2;
private static final int PROBE_INDEX = 1;
private static final int SMR_INDEX = 0;
private static final int PITR_INDEX = 7;
private static final int SMR_INVOKED_INDEX = 6;
@Override
public LispMapRequest readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException {
if (byteBuf.readerIndex() != 0) {
return null;
}
byte typeWithFlags = byteBuf.readByte();
// authoritative -> 1 bit
boolean authoritative = ByteOperator.getBit(typeWithFlags, AUTHORITATIVE_INDEX);
// mapDataPresent -> 1 bit
boolean mapDataPresent = ByteOperator.getBit(typeWithFlags, MAP_DATA_PRESENT_INDEX);
// probe -> 1 bit
boolean probe = ByteOperator.getBit(typeWithFlags, PROBE_INDEX);
// smr -> 1 bit
boolean smr = ByteOperator.getBit(typeWithFlags, SMR_INDEX);
byte reservedWithFlags = byteBuf.readByte();
// pitr -> 1 bit
boolean pitr = ByteOperator.getBit(reservedWithFlags, PITR_INDEX);
// smrInvoked -> 1 bit
boolean smrInvoked = ByteOperator.getBit(reservedWithFlags, SMR_INVOKED_INDEX);
// let's skip reserved field, only obtains ITR counter value
// assume that first 3 bits are all set as 0,
// remain 5 bits represent Itr Rloc Counter (IRC)
int irc = byteBuf.readUnsignedByte();
// record count -> 8 bits
int recordCount = byteBuf.readUnsignedByte();
// nonce -> 64 bits
long nonce = byteBuf.readLong();
LispAfiAddress sourceEid = new LispAfiAddress.AfiAddressReader().readFrom(byteBuf);
// deserialize a collection of RLOC addresses
List<LispAfiAddress> itrRlocs = Lists.newArrayList();
for (int i = 0; i < irc; i++) {
itrRlocs.add(new LispAfiAddress.AfiAddressReader().readFrom(byteBuf));
}
// deserialize a collection of EID records
List<LispEidRecord> eidRecords = Lists.newArrayList();
for (int i = 0; i < recordCount; i++) {
eidRecords.add(new LispEidRecord.EidRecordReader().readFrom(byteBuf));
}
return new DefaultRequestBuilder()
.withIsAuthoritative(authoritative)
.withIsMapDataPresent(mapDataPresent)
.withIsProbe(probe)
.withIsSmr(smr)
.withIsPitr(pitr)
.withIsSmrInvoked(smrInvoked)
.withNonce(nonce)
.withRecordCount((byte) recordCount)
.withSourceEid(sourceEid)
.withEidRecords(eidRecords)
.withItrRlocs(itrRlocs)
.build();
}
}
/**
* A LISP message writer for MapRequest message.
*/
public static final class RequestWriter implements LispMessageWriter<LispMapRequest> {
private static final int REQUEST_MSG_TYPE = 1;
private static final int REQUEST_SHIFT_BIT = 4;
private static final int AUTHORITATIVE_SHIFT_BIT = 3;
private static final int MAP_DATA_PRESENT_SHIFT_BIT = 2;
private static final int PROBE_SHIFT_BIT = 1;
private static final int PITR_SHIFT_BIT = 7;
private static final int SMR_INVOKED_SHIFT_BIT = 6;
private static final int ENABLE_BIT = 1;
private static final int DISABLE_BIT = 0;
@Override
public void writeTo(ByteBuf byteBuf, LispMapRequest message) throws LispWriterException {
// specify LISP message type
byte msgType = (byte) (REQUEST_MSG_TYPE << REQUEST_SHIFT_BIT);
// authoritative flag
byte authoritative = DISABLE_BIT;
if (message.isAuthoritative()) {
authoritative = (byte) (ENABLE_BIT << AUTHORITATIVE_SHIFT_BIT);
}
// map data present flag
byte mapDataPresent = DISABLE_BIT;
if (message.isMapDataPresent()) {
mapDataPresent = (byte) (ENABLE_BIT << MAP_DATA_PRESENT_SHIFT_BIT);
}
// probe flag
byte probe = DISABLE_BIT;
if (message.isProbe()) {
probe = (byte) (ENABLE_BIT << PROBE_SHIFT_BIT);
}
// SMR flag
byte smr = DISABLE_BIT;
if (message.isSmr()) {
smr = (byte) ENABLE_BIT;
}
byteBuf.writeByte((byte) (msgType + authoritative + mapDataPresent + probe + smr));
// PITR flag bit
byte pitr = DISABLE_BIT;
if (message.isPitr()) {
pitr = (byte) (ENABLE_BIT << PITR_SHIFT_BIT);
}
// SMR invoked flag bit
byte smrInvoked = DISABLE_BIT;
if (message.isSmrInvoked()) {
smrInvoked = (byte) (ENABLE_BIT << SMR_INVOKED_SHIFT_BIT);
}
byteBuf.writeByte((byte) (pitr + smrInvoked));
// ITR Rloc count
byteBuf.writeByte((byte) message.getItrRlocs().size());
// record count
byteBuf.writeByte(message.getRecordCount());
// nonce
byteBuf.writeLong(message.getNonce());
// Source EID AFI with Source EID address
AfiAddressWriter afiAddressWriter = new AfiAddressWriter();
afiAddressWriter.writeTo(byteBuf, message.getSourceEid());
// ITR RLOCs
List<LispAfiAddress> rlocs = message.getItrRlocs();
for (int i = 0; i < rlocs.size(); i++) {
afiAddressWriter.writeTo(byteBuf, rlocs.get(i));
}
// EID records
EidRecordWriter recordWriter = new EidRecordWriter();
List<LispEidRecord> records = message.getEids();
for (int i = 0; i < records.size(); i++) {
recordWriter.writeTo(byteBuf, records.get(i));
}
// TODO: handle Map-Reply record
}
}
}