blob: 75f73b51321b84534d6d1737e423edae1584ca12 [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 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 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, LispAfiAddress sourceEid,
List<LispAfiAddress> itrRlocs, List<LispEidRecord> eidRecords,
boolean authoritative, boolean mapDataPresent, boolean probe,
boolean smr, boolean pitr, boolean smrInvoked) {
this.nonce = nonce;
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 int getRecordCount() {
return eidRecords.size();
}
@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("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(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, sourceEid, authoritative,
mapDataPresent, probe, smr, pitr, smrInvoked);
}
public static final class DefaultRequestBuilder implements RequestBuilder {
private long nonce;
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 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, 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)
.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_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) (LispType.LISP_MAP_REQUEST.getTypeCode() << 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.getEids().size());
// 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
}
}
}