| /* |
| * Copyright 2015 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.pcepio.protocol.ver1; |
| |
| import java.util.LinkedList; |
| import java.util.ListIterator; |
| |
| import org.jboss.netty.buffer.ChannelBuffer; |
| import org.onosproject.pcepio.exceptions.PcepParseException; |
| import org.onosproject.pcepio.protocol.PcepTEObject; |
| import org.onosproject.pcepio.types.LocalTENodeDescriptorsTLV; |
| import org.onosproject.pcepio.types.PcepObjectHeader; |
| import org.onosproject.pcepio.types.PcepValueType; |
| import org.onosproject.pcepio.types.RemoteTENodeDescriptorsTLV; |
| import org.onosproject.pcepio.types.RoutingUniverseTLV; |
| import org.onosproject.pcepio.types.TELinkAttributesTlv; |
| import org.onosproject.pcepio.types.TELinkDescriptorsTLV; |
| import org.onosproject.pcepio.types.TENodeAttributesTlv; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.google.common.base.MoreObjects; |
| |
| /** |
| * Provides PCEP TE Object. |
| */ |
| public class PcepTEObjectVer1 implements PcepTEObject { |
| /* |
| * |
| reference: PCEP Extension for Transporting TE Data draft-dhodylee-pce-pcep-te-data-extn-02. |
| TE Object-Class is [TBD6]. |
| |
| Two Object-Type values are defined for the TE object: |
| |
| o TE Node: TE Object-Type is 1. |
| |
| o TE Link: TE Object-Type is 2. |
| |
| The format of the TE object body is as follows: |
| |
| 0 1 2 3 |
| 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | Protocol-ID | Flag |R|S| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | TE-ID | |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| // TLVs // |
| | | |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| */ |
| |
| protected static final Logger log = LoggerFactory.getLogger(PcepTEObjectVer1.class); |
| |
| public static final byte TE_OBJ_TYPE_NODE_VALUE = 1; |
| public static final byte TE_OBJ_TYPE_LINK_VALUE = 2; |
| |
| public static final byte TE_OBJ_CLASS = 101; //TBD6 in RFC. |
| public static final byte TE_OBJECT_VERSION = 1; |
| |
| // TE_OBJ_MINIMUM_LENGTH = TEObjectHeaderLen(4)+ TEObjectLen(8) |
| public static final short TE_OBJ_MINIMUM_LENGTH = 12; |
| |
| // Signaled ,all default values to be checked. |
| public static final byte DEFAULT_PROTOCOL_ID = 1; //IS-IS Level 1 |
| public static final boolean DEFAULT_R_FLAG = false; |
| public static final boolean DEFAULT_S_FLAG = false; |
| public static final int DEFAULT_TE_ID = 0; |
| |
| public static final int OBJECT_HEADER_LENGTH = 4; |
| public static final int RIGHT_SHIFT_ONE = 1; |
| public static final int RIGHT_FIRST_FLAG = 0x1; |
| public static final int FLAG_SET_R_FLAG = 0x2; |
| public static final int FLAG_SET_S_FLAG = 0x1; |
| public static final int MINIMUM_COMMON_HEADER_LENGTH = 4; |
| public static final int MINIMUM_TLV_HEADER_LENGTH = 4; |
| |
| public static final PcepObjectHeader DEFAULT_TE_OBJECT_HEADER = new PcepObjectHeader(TE_OBJ_CLASS, |
| TE_OBJ_TYPE_NODE_VALUE, PcepObjectHeader.REQ_OBJ_OPTIONAL_PROCESS, PcepObjectHeader.RSP_OBJ_PROCESSED, |
| TE_OBJ_MINIMUM_LENGTH); |
| |
| private PcepObjectHeader teObjHeader; |
| private byte yProtocolId; |
| // 2-flags |
| private boolean bRFlag; |
| private boolean bSFlag; |
| private int iTEId; |
| // Optional TLV |
| private LinkedList<PcepValueType> llOptionalTlv; |
| |
| /** |
| * Constructor to initialize variables. |
| * |
| * @param teObjHeader TE Object header |
| * @param yProtocolId Protocol-ID |
| * @param bRFlag R-flag |
| * @param bSFlag S-flag |
| * @param iTEId TE-ID |
| * @param llOptionalTlv linked list of Optional TLV |
| */ |
| public PcepTEObjectVer1(PcepObjectHeader teObjHeader, byte yProtocolId, boolean bRFlag, boolean bSFlag, int iTEId, |
| LinkedList<PcepValueType> llOptionalTlv) { |
| |
| this.teObjHeader = teObjHeader; |
| this.yProtocolId = yProtocolId; |
| this.bRFlag = bRFlag; |
| this.bSFlag = bSFlag; |
| this.iTEId = iTEId; |
| this.llOptionalTlv = llOptionalTlv; |
| } |
| |
| @Override |
| public PcepObjectHeader getTEObjHeader() { |
| return this.teObjHeader; |
| } |
| |
| @Override |
| public void setTEObjHeader(PcepObjectHeader obj) { |
| this.teObjHeader = obj; |
| } |
| |
| @Override |
| public byte getProtocolId() { |
| return this.yProtocolId; |
| } |
| |
| @Override |
| public void setProtocolId(byte yProtId) { |
| this.yProtocolId = yProtId; |
| } |
| |
| @Override |
| public boolean getRFlag() { |
| return this.bRFlag; |
| } |
| |
| @Override |
| public void setRFlag(boolean bRFlag) { |
| this.bRFlag = bRFlag; |
| } |
| |
| @Override |
| public boolean getSFlag() { |
| return this.bSFlag; |
| } |
| |
| @Override |
| public void setSFlag(boolean bSFlag) { |
| this.bSFlag = bSFlag; |
| } |
| |
| @Override |
| public int getTEId() { |
| return this.iTEId; |
| } |
| |
| @Override |
| public void setTEId(int iTEId) { |
| this.iTEId = iTEId; |
| } |
| |
| @Override |
| public LinkedList<PcepValueType> getOptionalTlv() { |
| return this.llOptionalTlv; |
| } |
| |
| @Override |
| public void setOptionalTlv(LinkedList<PcepValueType> llOptionalTlv) { |
| this.llOptionalTlv = llOptionalTlv; |
| } |
| |
| /** |
| * Reads from the channel buffer and returns Object of PcepTEObject. |
| * |
| * @param cb of type channel buffer |
| * @return Object of PcepTEObject |
| * @throws PcepParseException if mandatory fields are missing |
| */ |
| public static PcepTEObject read(ChannelBuffer cb) throws PcepParseException { |
| log.debug("read"); |
| |
| PcepObjectHeader teObjHeader; |
| byte yProtocolId; |
| // 2-flags |
| boolean bRFlag; |
| boolean bSFlag; |
| int iTEId; |
| LinkedList<PcepValueType> llOptionalTlv; |
| |
| teObjHeader = PcepObjectHeader.read(cb); |
| |
| //take only TEObject buffer. |
| ChannelBuffer tempCb = cb.readBytes(teObjHeader.getObjLen() - OBJECT_HEADER_LENGTH); |
| |
| yProtocolId = tempCb.readByte(); |
| //ignore first two bytes of Flags |
| tempCb.readShort(); |
| |
| Integer iTemp = (int) tempCb.readByte(); //read 3rd byte Flag |
| bSFlag = ((iTemp & FLAG_SET_S_FLAG) == FLAG_SET_S_FLAG) ? true : false; |
| bRFlag = ((iTemp & FLAG_SET_R_FLAG) == FLAG_SET_R_FLAG) ? true : false; |
| |
| iTEId = tempCb.readInt(); |
| |
| // parse optional TLV |
| llOptionalTlv = parseOptionalTlv(tempCb); |
| |
| return new PcepTEObjectVer1(teObjHeader, yProtocolId, bRFlag, bSFlag, iTEId, llOptionalTlv); |
| } |
| |
| @Override |
| public int write(ChannelBuffer cb) throws PcepParseException { |
| |
| //write Object header |
| int objStartIndex = cb.writerIndex(); |
| int objLenIndex = teObjHeader.write(cb); |
| |
| if (objLenIndex <= 0) { |
| throw new PcepParseException("ObjectLength Index is " + objLenIndex); |
| } |
| |
| //write Protocol ID |
| cb.writeByte(this.yProtocolId); |
| |
| //write Flag |
| cb.writeShort(0); |
| |
| byte bTemp = 0; |
| if (bSFlag) { |
| bTemp = FLAG_SET_S_FLAG; |
| } |
| |
| if (bRFlag) { |
| bTemp = (byte) (bTemp | FLAG_SET_R_FLAG); |
| } |
| cb.writeByte(bTemp); |
| |
| //write TEId |
| cb.writeInt(iTEId); |
| |
| // Add optional TLV |
| packOptionalTlv(cb); |
| |
| //Update object length now |
| int length = cb.writerIndex() - objStartIndex; |
| |
| //will be helpful during print(). |
| teObjHeader.setObjLen((short) length); |
| |
| cb.setShort(objLenIndex, (short) length); |
| |
| return cb.writerIndex(); |
| } |
| |
| /** |
| * Returns Linked list of PCEP Value Type. |
| * |
| * @param cb of channel buffer |
| * @return Linked list of PCEP Value Type |
| * @throws PcepParseException if mandatory fields are missing |
| */ |
| protected static LinkedList<PcepValueType> parseOptionalTlv(ChannelBuffer cb) throws PcepParseException { |
| |
| LinkedList<PcepValueType> llOutOptionalTlv; |
| |
| llOutOptionalTlv = new LinkedList<PcepValueType>(); |
| |
| while (MINIMUM_TLV_HEADER_LENGTH <= cb.readableBytes()) { |
| |
| PcepValueType tlv; |
| short hType = cb.readShort(); |
| short hLength = cb.readShort(); |
| long lValue = 0; |
| |
| switch (hType) { |
| |
| case RoutingUniverseTLV.TYPE: |
| lValue = cb.readLong(); |
| tlv = new RoutingUniverseTLV(lValue); |
| break; |
| case LocalTENodeDescriptorsTLV.TYPE: |
| tlv = LocalTENodeDescriptorsTLV.read(cb, hLength); |
| break; |
| case RemoteTENodeDescriptorsTLV.TYPE: |
| RemoteTENodeDescriptorsTLV.hLength = hLength; |
| tlv = RemoteTENodeDescriptorsTLV.read(cb); |
| break; |
| case TELinkDescriptorsTLV.TYPE: |
| tlv = TELinkDescriptorsTLV.read(cb, hLength); |
| break; |
| case TENodeAttributesTlv.TYPE: |
| tlv = TENodeAttributesTlv.read(cb, hLength); |
| break; |
| case TELinkAttributesTlv.TYPE: |
| tlv = TELinkAttributesTlv.read(cb, hLength); |
| break; |
| default: |
| throw new PcepParseException("Unsupported TLV type :" + hType); |
| } |
| |
| // Check for the padding |
| int pad = hLength % 4; |
| if (0 < pad) { |
| pad = 4 - pad; |
| if (pad <= cb.readableBytes()) { |
| cb.skipBytes(pad); |
| } |
| } |
| |
| llOutOptionalTlv.add(tlv); |
| } |
| |
| if (0 < cb.readableBytes()) { |
| |
| throw new PcepParseException("Optional Tlv parsing error. Extra bytes received."); |
| } |
| return llOutOptionalTlv; |
| } |
| |
| /** |
| * Returns the writer index. |
| * |
| * @param cb of type channel buffer |
| * @return the writer index. |
| */ |
| protected int packOptionalTlv(ChannelBuffer cb) { |
| |
| ListIterator<PcepValueType> listIterator = llOptionalTlv.listIterator(); |
| |
| while (listIterator.hasNext()) { |
| PcepValueType tlv = listIterator.next(); |
| |
| if (null == tlv) { |
| log.debug("TLV is null from OptionalTlv list"); |
| continue; |
| } |
| tlv.write(cb); |
| |
| // need to take care of padding |
| int pad = tlv.getLength() % 4; |
| |
| if (0 != pad) { |
| pad = 4 - pad; |
| for (int i = 0; i < pad; ++i) { |
| cb.writeByte((byte) 0); |
| } |
| } |
| } |
| return cb.writerIndex(); |
| } |
| |
| /** |
| * Builder class for PCEP te object. |
| */ |
| public static class Builder implements PcepTEObject.Builder { |
| private boolean bIsHeaderSet = false; |
| private boolean bIsProtocolIdSet = false; |
| private boolean bIsRFlagSet = false; |
| private boolean bIsSFlagSet = false; |
| private boolean bIsTEIdSet = false; |
| |
| private PcepObjectHeader teObjHeader; |
| private byte yProtocolId; |
| private boolean bRFlag; |
| private boolean bSFlag; |
| private int iTEId; |
| private LinkedList<PcepValueType> llOptionalTlv = new LinkedList<PcepValueType>(); |
| |
| private boolean bIsPFlagSet = false; |
| private boolean bPFlag; |
| |
| private boolean bIsIFlagSet = false; |
| private boolean bIFlag; |
| |
| @Override |
| public PcepTEObject build() { |
| PcepObjectHeader teObjHeader = this.bIsHeaderSet ? this.teObjHeader : DEFAULT_TE_OBJECT_HEADER; |
| |
| byte yProtocolId = this.bIsProtocolIdSet ? this.yProtocolId : DEFAULT_PROTOCOL_ID; |
| boolean bRFlag = this.bIsRFlagSet ? this.bRFlag : DEFAULT_R_FLAG; |
| boolean bSFlag = this.bIsSFlagSet ? this.bSFlag : DEFAULT_S_FLAG; |
| int iTEId = this.bIsTEIdSet ? this.iTEId : DEFAULT_TE_ID; |
| |
| if (bIsPFlagSet) { |
| teObjHeader.setPFlag(bPFlag); |
| } |
| |
| if (bIsIFlagSet) { |
| teObjHeader.setIFlag(bIFlag); |
| } |
| |
| return new PcepTEObjectVer1(teObjHeader, yProtocolId, bRFlag, bSFlag, iTEId, llOptionalTlv); |
| |
| } |
| |
| @Override |
| public PcepObjectHeader getTEObjHeader() { |
| return this.teObjHeader; |
| } |
| |
| @Override |
| public Builder setTEObjHeader(PcepObjectHeader obj) { |
| this.teObjHeader = obj; |
| this.bIsHeaderSet = true; |
| return this; |
| } |
| |
| @Override |
| public byte getProtocolId() { |
| return this.yProtocolId; |
| } |
| |
| @Override |
| public Builder setProtocolId(byte yProtId) { |
| this.yProtocolId = yProtId; |
| this.bIsProtocolIdSet = true; |
| return this; |
| } |
| |
| @Override |
| public boolean getRFlag() { |
| return this.bRFlag; |
| } |
| |
| @Override |
| public Builder setRFlag(boolean bRFlag) { |
| this.bRFlag = bRFlag; |
| this.bIsRFlagSet = true; |
| return this; |
| } |
| |
| @Override |
| public boolean getSFlag() { |
| return this.bSFlag; |
| } |
| |
| @Override |
| public Builder setSFlag(boolean bSFlag) { |
| this.bSFlag = bSFlag; |
| this.bIsSFlagSet = true; |
| return this; |
| } |
| |
| @Override |
| public int getTEId() { |
| return this.iTEId; |
| } |
| |
| @Override |
| public Builder setTEId(int iTEId) { |
| this.iTEId = iTEId; |
| this.bIsTEIdSet = true; |
| return this; |
| } |
| |
| @Override |
| public LinkedList<PcepValueType> getOptionalTlv() { |
| return this.llOptionalTlv; |
| } |
| |
| @Override |
| public Builder setOptionalTlv(LinkedList<PcepValueType> llOptionalTlv) { |
| this.llOptionalTlv = llOptionalTlv; |
| return this; |
| } |
| |
| @Override |
| public Builder setPFlag(boolean value) { |
| this.bPFlag = value; |
| this.bIsPFlagSet = true; |
| return this; |
| } |
| |
| @Override |
| public Builder setIFlag(boolean value) { |
| this.bIFlag = value; |
| this.bIsIFlagSet = true; |
| return this; |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return MoreObjects.toStringHelper(getClass()).add("ObjectHeader", teObjHeader).add("ProtocolId", yProtocolId) |
| .add("RFlag", (bRFlag) ? 1 : 0).add("SFlag", (bSFlag) ? 1 : 0).add("TeId", iTEId) |
| .add("OptionalTlv", llOptionalTlv).toString(); |
| } |
| } |