/* * 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.isis.io.isispacket.pdu; import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.primitives.Bytes; import org.jboss.netty.buffer.ChannelBuffer; import org.onosproject.isis.io.isispacket.IsisHeader; import org.onosproject.isis.io.isispacket.tlv.IsisTlv; import org.onosproject.isis.io.isispacket.tlv.TlvFinder; import org.onosproject.isis.io.isispacket.tlv.TlvHeader; import org.onosproject.isis.io.isispacket.tlv.TlvType; import org.onosproject.isis.io.isispacket.tlv.TlvsToBytes; import org.onosproject.isis.io.util.IsisUtil; import java.util.ArrayList; import java.util.List; /** * Representation of an ISIS Link State packet. * Each Link State packet carries a collection of TLVs * Several TLVs may be included in a single packet. */ public class LsPdu extends IsisHeader { /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Intra-domain Routing Protocol Discriminator | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Length Indicator | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Version/Protocol ID Extension | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ID Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | R | R | R | PDU Type | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Version | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Maximum area address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | PDU Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Remaining Lifetime | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | LSP ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | PDU Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | P | ATT | LSPDBOL | IS Type | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Variable Lengths Fields | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ LS PDU Format REFERENCE : ISO/IECĀ 10589 */ private int pduLength; private int remainingLifeTime; private String lspId; private int sequenceNumber; private int checkSum; private boolean partitionRepair; private AttachedToOtherAreas attachedToOtherAreas; private boolean lspDbol; private byte typeBlock; private byte intermediateSystemType; private List<IsisTlv> variableLengths = new ArrayList<>(); /** * Creates an instance of Link State packet. * * @param isisHeader isis header details */ public LsPdu(IsisHeader isisHeader) { populateHeader(isisHeader); } /** * Returns the ISIS tlvs. * * @return tlvs */ public List<IsisTlv> tlvs() { return this.variableLengths; } /** * Adds the isis tlv to the list for the link state PDU. * * @param isisTlv isis tlv */ public void addTlv(IsisTlv isisTlv) { variableLengths.add(isisTlv); } /** * Returns the remaining time of the link state pdu. * Number of seconds before LSP considered expired * * @return remainingTime remaining time */ public int remainingLifeTime() { return remainingLifeTime; } /** * Sets the remaining time for the link state pdu. * * @param remainingLifeTime remaining time */ public void setRemainingLifeTime(int remainingLifeTime) { this.remainingLifeTime = remainingLifeTime; } /** * Returns the link state database overload. * * @return lspdbol link state database overload */ public boolean lspDbol() { return lspDbol; } /** * Sets the link state database overload for this pdu. * * @param lspDbol link state database overload */ public void setLspDbol(boolean lspDbol) { this.lspDbol = lspDbol; } /** * Returns the type block. * * @return type block */ public byte typeBlock() { return typeBlock; } /** * Sets the type block. * * @param typeBlock type block */ public void setTypeBlock(byte typeBlock) { this.typeBlock = typeBlock; } /** * Returns the sequence number of LSP. * * @return sequenceNumber sequence number */ public int sequenceNumber() { return sequenceNumber; } /** * Sets the sequence nubmer for LSP. * * @param sequenceNumber sequence number */ public void setSequenceNumber(int sequenceNumber) { this.sequenceNumber = sequenceNumber; } /** * Returns the checksum of LSP from Source ID to end. * * @return checkSum check sum */ public int checkSum() { return checkSum; } /** * Sets the checksum for LSP from Source ID to end. * * @param checkSum check sum */ public void setCheckSum(int checkSum) { this.checkSum = checkSum; } /** * Returns the partition repair value of the intermediate system. * * @return partitionRepair partition repair */ public boolean partitionRepair() { return partitionRepair; } /** * Sets partition repair value for the intermediate system. * * @param partitionRepair partition repair */ public void setPartitionRepair(boolean partitionRepair) { this.partitionRepair = partitionRepair; } /** * Returns the value of intermediate system attached field. * return values based on type Default Metric, Delay Metric, Expense Metric, Error Metric * * @return attachedToOtherAreas attached to other areas */ public AttachedToOtherAreas attachedToOtherAreas() { return attachedToOtherAreas; } /** * Sets the value for intermediate system attached field. * it will pass values based on type Default Metric, Delay Metric, Expense Metric, Error Metric * * @param attachedToOtherAreas attached to other areas */ public void setAttachedToOtherAreas(AttachedToOtherAreas attachedToOtherAreas) { this.attachedToOtherAreas = attachedToOtherAreas; } /** * Returns the intermediate system type. * type will be level 1 or level 2 * * @return intermediateSystemType intermediate system type */ public byte intermediateSystemType() { return intermediateSystemType; } /** * Sets the value for intermediate system. * type will be level 1 or level 2 * * @param intermediateSystemType intermediate system type */ public void setIntermediateSystemType(byte intermediateSystemType) { this.intermediateSystemType = intermediateSystemType; } /** * Returns the link state ID of link state packet. * System ID of the source of link state PDU * * @return lspId link state packet ID */ public String lspId() { return lspId; } /** * Sets the link state ID for link state packet. * System ID of the source of link state PDU * * @param lspId link state packet ID */ public void setLspId(String lspId) { this.lspId = lspId; } /** * Returns the packet data unit length of link state packet. * Entire length of this PDU, in octets * * @return pduLength packet data unit length */ public int pduLength() { return pduLength; } /** * Sets the packet data unit length for link state packet. * Entire Length of this PDU, in octets * * @param pduLength packet data length */ public void setPduLength(int pduLength) { this.pduLength = pduLength; } @Override public void readFrom(ChannelBuffer channelBuffer) { this.setPduLength(channelBuffer.readUnsignedShort()); this.setRemainingLifeTime(channelBuffer.readUnsignedShort()); //lsp id + 2 value byte[] tempByteArray = new byte[IsisUtil.ID_PLUS_TWO_BYTE]; channelBuffer.readBytes(tempByteArray, 0, IsisUtil.ID_PLUS_TWO_BYTE); this.setLspId(IsisUtil.systemIdPlus(tempByteArray)); //sequence number 4 this.setSequenceNumber(channelBuffer.readInt()); this.setCheckSum(channelBuffer.readUnsignedShort()); int typeTemp = channelBuffer.readUnsignedByte(); byte isTypeByte = (byte) typeTemp; String tempValue = String.format("%8s", Integer.toBinaryString(isTypeByte & 0xFF)).replace(' ', '0'); int pBit = Integer.parseInt(new Character(tempValue.charAt(0)).toString()); if (pBit == 1) { this.setPartitionRepair(true); } else { this.setPartitionRepair(false); } int attValue = Integer.parseInt(tempValue.substring(1, 5), 2); switch (AttachedToOtherAreas.get(attValue)) { case DEFAULTMETRIC: this.setAttachedToOtherAreas(AttachedToOtherAreas.DEFAULTMETRIC); break; case DELAYMETRIC: this.setAttachedToOtherAreas(AttachedToOtherAreas.DELAYMETRIC); break; case EXPENSEMETRIC: this.setAttachedToOtherAreas(AttachedToOtherAreas.EXPENSEMETRIC); break; case ERRORMETRIC: this.setAttachedToOtherAreas(AttachedToOtherAreas.ERRORMETRIC); break; case NONE: this.setAttachedToOtherAreas(AttachedToOtherAreas.NONE); break; default: break; } int lspdbol = Integer.parseInt(new Character(tempValue.charAt(5)).toString()); if (lspdbol == 1) { this.setLspDbol(true); } else { this.setLspDbol(false); } int isType = Integer.parseInt(tempValue.substring(6, 8), 2); byte isTypeByteValue = (byte) isType; this.setIntermediateSystemType(isTypeByteValue); //tlv here while (channelBuffer.readableBytes() > 0) { TlvHeader tlvHeader = new TlvHeader(); tlvHeader.setTlvType(channelBuffer.readUnsignedByte()); tlvHeader.setTlvLength(channelBuffer.readUnsignedByte()); TlvType tlvValue = TlvType.get(tlvHeader.tlvType()); if (tlvValue != null) { IsisTlv tlv = TlvFinder.findTlv(tlvHeader, channelBuffer.readBytes(tlvHeader.tlvLength())); if (tlv != null) { this.variableLengths.add(tlv); } } else { channelBuffer.readBytes(tlvHeader.tlvLength()); } } } @Override public byte[] asBytes() { byte[] lspMessage = null; byte[] helloHeader = l1l2IsisPduHeader(); byte[] lspBody = l1l2LsPduBody(); lspMessage = Bytes.concat(helloHeader, lspBody); return lspMessage; } /** * Builds ISIS PDU header from ISIS message. * * @return headerList ISIS PDU header */ public byte[] l1l2IsisPduHeader() { List<Byte> headerList = new ArrayList<>(); headerList.add(this.irpDiscriminator()); headerList.add((byte) IsisUtil.getPduHeaderLength(this.pduType())); headerList.add(this.version()); headerList.add(this.idLength()); headerList.add((byte) this.pduType()); headerList.add(this.version2()); headerList.add(this.reserved()); headerList.add(this.maximumAreaAddresses()); return Bytes.toArray(headerList); } /** * Builds link state PDU body from ISIS message. * * @return bodyList link state PDU body */ public byte[] l1l2LsPduBody() { List<Byte> bodyList = new ArrayList<>(); bodyList.addAll(Bytes.asList(IsisUtil.convertToTwoBytes(this.pduLength()))); bodyList.addAll(Bytes.asList(IsisUtil.convertToTwoBytes(this.remainingLifeTime()))); bodyList.addAll(IsisUtil.sourceAndLanIdToBytes(this.lspId())); bodyList.addAll(Bytes.asList(IsisUtil.convertToFourBytes(this.sequenceNumber()))); bodyList.addAll(Bytes.asList(IsisUtil.convertToTwoBytes(this.checkSum()))); String temString = ""; if (this.partitionRepair()) { temString = "1" + temString; } else { temString = "0" + temString; } switch (this.attachedToOtherAreas()) { case ERRORMETRIC: temString = temString + "1000"; break; case EXPENSEMETRIC: temString = temString + "0100"; break; case DELAYMETRIC: temString = temString + "0010"; break; case DEFAULTMETRIC: temString = temString + "0001"; break; case NONE: temString = temString + "0000"; break; default: break; } if (this.lspDbol()) { temString = temString + "1"; } else { temString = temString + "0"; } String isType = Integer.toBinaryString(this.intermediateSystemType()); if (isType.length() % 2 != 0) { isType = "0" + isType; } temString = temString + isType; bodyList.add((byte) Integer.parseInt(temString, 2)); for (IsisTlv isisTlv : variableLengths) { bodyList.addAll(TlvsToBytes.tlvToBytes(isisTlv)); } return Bytes.toArray(bodyList); } @Override public String toString() { return MoreObjects.toStringHelper(getClass()) .omitNullValues() .add("pduLength", pduLength) .add("remainingLifeTime", remainingLifeTime) .add("lspId", lspId) .add("sequenceNumber", sequenceNumber) .add("checkSum", checkSum) .add("partitionRepair", partitionRepair) .add("lspDbol", lspDbol) .add("typeBlock", typeBlock) .add("intermediateSystemType", intermediateSystemType) .toString(); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } LsPdu that = (LsPdu) o; return Objects.equal(pduLength, that.pduLength) && Objects.equal(remainingLifeTime, that.remainingLifeTime) && Objects.equal(lspId, that.lspId) && Objects.equal(sequenceNumber, that.sequenceNumber) && Objects.equal(checkSum, that.checkSum) && Objects.equal(partitionRepair, that.partitionRepair) && Objects.equal(lspDbol, that.lspDbol) && Objects.equal(typeBlock, that.typeBlock) && Objects.equal(intermediateSystemType, that.intermediateSystemType); } @Override public int hashCode() { return Objects.hashCode(pduLength, remainingLifeTime, lspId, sequenceNumber, checkSum, partitionRepair, lspDbol, typeBlock, intermediateSystemType); } }