/* * 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.protocols.DefaultLispLocator.LocatorReader; import org.onosproject.lisp.msg.protocols.DefaultLispLocator.LocatorWriter; import org.onosproject.lisp.msg.types.LispAfiAddress; import org.onosproject.lisp.msg.exceptions.LispReaderException; import org.onosproject.lisp.msg.exceptions.LispWriterException; 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 implementation of LispMapRecord. */ public final class DefaultLispMapRecord extends AbstractLispRecord implements LispMapRecord { private final List<LispLocator> locators; static final MapRecordWriter WRITER; static { WRITER = new MapRecordWriter(); } /** * 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 locators a collection of locators */ private DefaultLispMapRecord(int recordTtl, byte maskLength, LispMapReplyAction action, boolean authoritative, short mapVersionNumber, LispAfiAddress eidPrefixAfi, List<LispLocator> locators) { super(recordTtl, maskLength, action, authoritative, mapVersionNumber, eidPrefixAfi); this.locators = locators; } @Override public int getLocatorCount() { return locators.size(); } @Override public List<LispLocator> getLocators() { return ImmutableList.copyOf(locators); } @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("locators", locators) .toString(); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } DefaultLispMapRecord that = (DefaultLispMapRecord) 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(locators, that.locators); } @Override public int hashCode() { return Objects.hashCode(recordTtl, maskLength, action, authoritative, mapVersionNumber, eidPrefixAfi, locators); } public static final class DefaultMapRecordBuilder extends AbstractRecordBuilder<MapRecordBuilder> implements MapRecordBuilder { private List<LispLocator> locators = Lists.newArrayList(); @Override public MapRecordBuilder withLocators(List<LispLocator> locators) { if (locators != null) { this.locators = ImmutableList.copyOf(locators); } return this; } @Override public LispMapRecord build() { checkNotNull(eidPrefixAfi, "Must specify an EID prefix"); return new DefaultLispMapRecord(recordTtl, maskLength, action, authoritative, mapVersionNumber, eidPrefixAfi, locators); } } /** * A LISP message reader for MapRecord portion. */ public static final class MapRecordReader implements LispMessageReader<LispMapRecord> { private static final int AUTHORITATIVE_INDEX = 4; private static final int RESERVED_SKIP_LENGTH = 1; private static final int REPLY_ACTION_SHIFT_BIT = 5; @Override public LispMapRecord readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException { // Record TTL -> 32 bits int recordTtl = byteBuf.readInt(); // Locator count -> 8 bits int locatorCount = byteBuf.readUnsignedByte(); // EID mask length -> 8 bits byte maskLength = (byte) byteBuf.readUnsignedByte(); byte actionWithFlag = (byte) byteBuf.readUnsignedByte(); // action -> 3 bit 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); // 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<LispLocator> locators = Lists.newArrayList(); for (int i = 0; i < locatorCount; i++) { locators.add(new LocatorReader().readFrom(byteBuf)); } return new DefaultMapRecordBuilder() .withRecordTtl(recordTtl) .withMaskLength(maskLength) .withAction(action) .withIsAuthoritative(authoritative) .withMapVersionNumber(mapVersionNumber) .withLocators(locators) .withEidPrefixAfi(eidPrefixAfi) .build(); } } /** * A LISP message writer for MapRecord portion. */ public static final class MapRecordWriter implements LispMessageWriter<LispMapRecord> { private static final int REPLY_ACTION_SHIFT_BIT = 5; private static final int AUTHORITATIVE_FLAG_SHIFT_BIT = 4; private static final int ENABLE_BIT = 1; private static final int DISABLE_BIT = 0; @Override public void writeTo(ByteBuf byteBuf, LispMapRecord message) throws LispWriterException { // record TTL byteBuf.writeInt(message.getRecordTtl()); // locator count byteBuf.writeByte((byte) message.getLocators().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_FLAG_SHIFT_BIT; } byteBuf.writeByte((byte) (action + authoritative)); // fill zero into reserved field byteBuf.writeByte((short) 0); // map version number byteBuf.writeShort(message.getMapVersionNumber()); // EID prefix AFI with EID prefix AfiAddressWriter afiAddressWriter = new AfiAddressWriter(); afiAddressWriter.writeTo(byteBuf, message.getEidPrefixAfi()); // serialize locator LocatorWriter recordWriter = new LocatorWriter(); List<LispLocator> locators = message.getLocators(); for (int i = 0; i < locators.size(); i++) { recordWriter.writeTo(byteBuf, locators.get(i)); } } } }