/* * Copyright 2015-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.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.PcepLspObject; import org.onosproject.pcepio.types.PcepErrorDetailInfo; import org.onosproject.pcepio.types.PcepObjectHeader; import org.onosproject.pcepio.types.PcepValueType; import org.onosproject.pcepio.types.StatefulIPv4LspIdentifiersTlv; import org.onosproject.pcepio.types.StatefulLspDbVerTlv; import org.onosproject.pcepio.types.StatefulLspErrorCodeTlv; import org.onosproject.pcepio.types.StatefulRsvpErrorSpecTlv; import org.onosproject.pcepio.types.SymbolicPathNameTlv; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.MoreObjects; /** * Provides PCEP lsp object. */ public class PcepLspObjectVer1 implements PcepLspObject { /* message format. Reference : draft-ietf-pce-stateful-pce-11, section 7.3. 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Object-Class | OT |Res|P|I| Object Length (bytes) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | PLSP-ID | Flag |C| O|A|R|S|D| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // TLVs // | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ The LSP Object format */ protected static final Logger log = LoggerFactory.getLogger(PcepLspObjectVer1.class); public static final byte LSP_OBJ_TYPE = 1; public static final byte LSP_OBJ_CLASS = 32; public static final byte LSP_OBJECT_VERSION = 1; // LSP_OBJ_MINIMUM_LENGTH = CommonHeaderLen(4)+ LspObjectHeaderLen(4)+TlvAssumedMinLength(8) public static final short LSP_OBJ_MINIMUM_LENGTH = 16; public static final int DEFAULT_PLSPID = 0; public static final byte DEFAULT_OFLAG = 1; public static final boolean DEFAULT_AFLAG = false; public static final boolean DEFAULT_RFLAG = false; public static final boolean DEFAULT_SFLAG = false; public static final boolean DEFAULT_DFLAG = false; public static final boolean DEFAULT_CFLAG = false; public static final int OBJECT_HEADER_LENGTH = 4; public static final int PLSPID_SHIFT_VALUE = 12; public static final int CFLAG_SHIFT_VALUE = 7; public static final int OFLAG_SHIFT_VALUE = 4; public static final int AFLAG_SHIFT_VALUE = 3; public static final int RFLAG_SHIFT_VALUE = 2; public static final int SFLAG_SHIFT_VALUE = 1; public static final int PLSPID_TEMP_SHIFT_VALUE = 0xFFFFF000; public static final int CFLAG_TEMP_SHIFT_VALUE = 0x80; public static final int OFLAG_TEMP_SHIFT_VALUE = 0x70; public static final int AFLAG_TEMP_SHIFT_VALUE = 0x08; public static final int RFLAG_TEMP_SHIFT_VALUE = 0x04; public static final int SFLAG_TEMP_SHIFT_VALUE = 0x02; public static final int DFLAG_TEMP_SHIFT_VALUE = 0x01; public static final int BIT_SET = 1; public static final int BIT_RESET = 0; public static final int MINIMUM_COMMON_HEADER_LENGTH = 4; static final PcepObjectHeader DEFAULT_LSP_OBJECT_HEADER = new PcepObjectHeader(LSP_OBJ_CLASS, LSP_OBJ_TYPE, PcepObjectHeader.REQ_OBJ_OPTIONAL_PROCESS, PcepObjectHeader.RSP_OBJ_PROCESSED, LSP_OBJ_MINIMUM_LENGTH); private PcepObjectHeader lspObjHeader; private int iPlspId; // 3-bits private byte yOFlag; private boolean bAFlag; private boolean bRFlag; private boolean bSFlag; private boolean bDFlag; private boolean bCFlag; // Optional TLV private LinkedList<PcepValueType> llOptionalTlv; /** * Constructor to initialize all the member variables. * * @param lspObjHeader lsp object header * @param iPlspId plsp id * @param yOFlag O flag * @param bAFlag A flag * @param bRFlag R flag * @param bSFlag S flag * @param bDFlag D flag * @param bCFlag C flag * @param llOptionalTlv list of optional tlv */ public PcepLspObjectVer1(PcepObjectHeader lspObjHeader, int iPlspId, byte yOFlag, boolean bAFlag, boolean bRFlag, boolean bSFlag, boolean bDFlag, boolean bCFlag, LinkedList<PcepValueType> llOptionalTlv) { this.lspObjHeader = lspObjHeader; this.iPlspId = iPlspId; this.yOFlag = yOFlag; this.bAFlag = bAFlag; this.bRFlag = bRFlag; this.bSFlag = bSFlag; this.bDFlag = bDFlag; this.bCFlag = bCFlag; this.llOptionalTlv = llOptionalTlv; } /** * Sets lsp Object Header. * * @param obj lsp object header */ public void setLspObjHeader(PcepObjectHeader obj) { this.lspObjHeader = obj; } @Override public void setPlspId(int iPlspId) { this.iPlspId = iPlspId; } @Override public void setCFlag(boolean bCFlag) { this.bCFlag = bCFlag; } @Override public void setOFlag(byte yOFlag) { this.yOFlag = yOFlag; } @Override public void setAFlag(boolean bAFlag) { this.bAFlag = bAFlag; } @Override public void setRFlag(boolean bRFlag) { this.bRFlag = bRFlag; } @Override public void setSFlag(boolean bSFlag) { this.bSFlag = bSFlag; } @Override public void setDFlag(boolean bDFlag) { this.bDFlag = bDFlag; } /** * Returns lsp object header. * * @return lspObjHeader */ public PcepObjectHeader getLspObjHeader() { return this.lspObjHeader; } @Override public int getPlspId() { return this.iPlspId; } @Override public boolean getCFlag() { return this.bCFlag; } @Override public byte getOFlag() { return this.yOFlag; } @Override public boolean getAFlag() { return this.bAFlag; } @Override public boolean getRFlag() { return this.bRFlag; } @Override public boolean getSFlag() { return this.bSFlag; } @Override public boolean getDFlag() { return this.bDFlag; } @Override public LinkedList<PcepValueType> getOptionalTlv() { return this.llOptionalTlv; } @Override public void setOptionalTlv(LinkedList<PcepValueType> llOptionalTlv) { this.llOptionalTlv = llOptionalTlv; } /** * Parse channel buffer and returns object of PcepLspObject. * * @param cb of type channel buffer * @return object of PcepLspObject * @throws PcepParseException when lsp object is not present in channel buffer */ public static PcepLspObject read(ChannelBuffer cb) throws PcepParseException { PcepObjectHeader lspObjHeader; int iPlspId; // 3-bits byte yOFlag; boolean bAFlag; boolean bRFlag; boolean bSFlag; boolean bDFlag; boolean bCFlag; // Optional TLV LinkedList<PcepValueType> llOptionalTlv = new LinkedList<>(); lspObjHeader = PcepObjectHeader.read(cb); if (lspObjHeader.getObjClass() != PcepLspObjectVer1.LSP_OBJ_CLASS) { throw new PcepParseException(PcepErrorDetailInfo.ERROR_TYPE_6, PcepErrorDetailInfo.ERROR_VALUE_8); } //take only LspObject buffer. ChannelBuffer tempCb = cb.readBytes(lspObjHeader.getObjLen() - OBJECT_HEADER_LENGTH); Integer iTemp = tempCb.readInt(); iPlspId = (iTemp & PLSPID_TEMP_SHIFT_VALUE) >> PLSPID_SHIFT_VALUE; bCFlag = ((iTemp & CFLAG_TEMP_SHIFT_VALUE) >> CFLAG_SHIFT_VALUE) > 0; Integer iX = (iTemp & OFLAG_TEMP_SHIFT_VALUE) >> OFLAG_SHIFT_VALUE; yOFlag = iX.byteValue(); iX = (iTemp & AFLAG_TEMP_SHIFT_VALUE) >> AFLAG_SHIFT_VALUE; bAFlag = iX > 0; iX = (iTemp & RFLAG_TEMP_SHIFT_VALUE) >> RFLAG_SHIFT_VALUE; bRFlag = iX > 0; iX = (iTemp & SFLAG_TEMP_SHIFT_VALUE) >> SFLAG_SHIFT_VALUE; bSFlag = iX > 0; iX = iTemp & DFLAG_TEMP_SHIFT_VALUE; bDFlag = iX > 0; // parse optional TLV llOptionalTlv = parseOptionalTlv(tempCb); return new PcepLspObjectVer1(lspObjHeader, iPlspId, yOFlag, bAFlag, bRFlag, bSFlag, bDFlag, bCFlag, llOptionalTlv); } @Override public int write(ChannelBuffer cb) throws PcepParseException { //write Object header int objStartIndex = cb.writerIndex(); int objLenIndex = lspObjHeader.write(cb); if (objLenIndex <= 0) { throw new PcepParseException("Failed to write lsp object header. Index " + objLenIndex); } int iTemp = iPlspId << PLSPID_SHIFT_VALUE; iTemp = iTemp | (((bCFlag) ? BIT_SET : BIT_RESET) << CFLAG_SHIFT_VALUE); iTemp = iTemp | (yOFlag << OFLAG_SHIFT_VALUE); byte bFlag; iTemp = bAFlag ? (iTemp | AFLAG_TEMP_SHIFT_VALUE) : iTemp; bFlag = (bRFlag) ? (byte) BIT_SET : BIT_RESET; iTemp = iTemp | (bFlag << RFLAG_SHIFT_VALUE); bFlag = (bSFlag) ? (byte) BIT_SET : BIT_RESET; iTemp = iTemp | (bFlag << SFLAG_SHIFT_VALUE); bFlag = (bDFlag) ? (byte) BIT_SET : BIT_RESET; iTemp = iTemp | bFlag; cb.writeInt(iTemp); // Add optional TLV packOptionalTlv(cb); //Update object length now int length = cb.writerIndex() - objStartIndex; //will be helpful during print(). lspObjHeader.setObjLen((short) length); // As per RFC the length of object should be // multiples of 4 cb.setShort(objLenIndex, (short) length); return length; } /** * Returns Linked list of optional tlvs. * * @param cb of channel buffer. * @return list of optional tlvs * @throws PcepParseException when unsupported tlv is received */ protected static LinkedList<PcepValueType> parseOptionalTlv(ChannelBuffer cb) throws PcepParseException { LinkedList<PcepValueType> llOutOptionalTlv; llOutOptionalTlv = new LinkedList<>(); while (MINIMUM_COMMON_HEADER_LENGTH <= cb.readableBytes()) { PcepValueType tlv = null; short hType = cb.readShort(); short hLength = cb.readShort(); int iValue = 0; switch (hType) { case StatefulIPv4LspIdentifiersTlv.TYPE: tlv = StatefulIPv4LspIdentifiersTlv.read(cb); break; case StatefulLspErrorCodeTlv.TYPE: iValue = cb.readInt(); tlv = new StatefulLspErrorCodeTlv(iValue); break; case StatefulRsvpErrorSpecTlv.TYPE: tlv = StatefulRsvpErrorSpecTlv.read(cb); break; case SymbolicPathNameTlv.TYPE: tlv = SymbolicPathNameTlv.read(cb, hLength); break; case StatefulLspDbVerTlv.TYPE: tlv = StatefulLspDbVerTlv.read(cb); break; default: // Skip the unknown TLV. cb.skipBytes(hLength); log.info("Received unsupported TLV type :" + hType + " in LSP object."); } // Check for the padding int pad = hLength % 4; if (0 < pad) { pad = 4 - pad; if (pad <= cb.readableBytes()) { cb.skipBytes(pad); } } if (tlv != null) { llOutOptionalTlv.add(tlv); } } if (0 < cb.readableBytes()) { throw new PcepParseException("Optional Tlv parsing error. Extra bytes received."); } return llOutOptionalTlv; } /** * returns writer index. * * @param cb of type channel buffer * @return length of bytes written to channel buffer */ protected int packOptionalTlv(ChannelBuffer cb) { ListIterator<PcepValueType> listIterator = llOptionalTlv.listIterator(); int startIndex = cb.writerIndex(); while (listIterator.hasNext()) { PcepValueType tlv = listIterator.next(); if (tlv == null) { 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() - startIndex; } /** * Builder class for PCEP lsp Object. */ public static class Builder implements PcepLspObject.Builder { private boolean bIsHeaderSet = false; private boolean bIsPlspIdSet = false; private boolean bIsOFlagSet = false; private boolean bIsRFlagSet = false; private boolean bIsAFlagSet = false; private boolean bIsDFlagSet = false; private boolean bIsSFlagSet = false; private boolean bIsCFlagSet = false; private PcepObjectHeader lspObjHeader; private byte yOFlag; private boolean bAFlag; private boolean bDFlag; private boolean bSFlag; private boolean bRFlag; private boolean bCFlag; LinkedList<PcepValueType> llOptionalTlv = null; private int plspId; private boolean bIsPFlagSet = false; private boolean bPFlag; private boolean bIsIFlagSet = false; private boolean bIFlag; @Override public PcepLspObject build() { PcepObjectHeader lspObjHeader = this.bIsHeaderSet ? this.lspObjHeader : DEFAULT_LSP_OBJECT_HEADER; int plspId = this.bIsPlspIdSet ? this.plspId : DEFAULT_PLSPID; byte yOFlag = this.bIsOFlagSet ? this.yOFlag : DEFAULT_OFLAG; boolean bAFlag = this.bIsAFlagSet ? this.bAFlag : DEFAULT_AFLAG; boolean bRFlag = this.bIsRFlagSet ? this.bRFlag : DEFAULT_RFLAG; boolean bSFlag = this.bIsSFlagSet ? this.bSFlag : DEFAULT_SFLAG; boolean bDFlag = this.bIsDFlagSet ? this.bDFlag : DEFAULT_DFLAG; boolean bCFlag = this.bIsCFlagSet ? this.bCFlag : DEFAULT_CFLAG; if (bIsPFlagSet) { lspObjHeader.setPFlag(bPFlag); } if (bIsIFlagSet) { lspObjHeader.setIFlag(bIFlag); } return new PcepLspObjectVer1(lspObjHeader, plspId, yOFlag, bAFlag, bRFlag, bSFlag, bDFlag, bCFlag, llOptionalTlv); } @Override public PcepObjectHeader getLspObjHeader() { return this.lspObjHeader; } @Override public Builder setLspObjHeader(PcepObjectHeader obj) { this.lspObjHeader = obj; this.bIsHeaderSet = true; return this; } @Override public int getPlspId() { return this.plspId; } @Override public Builder setPlspId(int value) { this.plspId = value; this.bIsPlspIdSet = true; return this; } @Override public boolean getCFlag() { return this.bCFlag; } @Override public Builder setCFlag(boolean value) { this.bCFlag = value; this.bIsCFlagSet = true; return this; } @Override public byte getOFlag() { return this.yOFlag; } @Override public Builder setOFlag(byte value) { this.yOFlag = value; this.bIsOFlagSet = true; return this; } @Override public boolean getAFlag() { return this.bAFlag; } @Override public Builder setAFlag(boolean value) { this.bAFlag = value; this.bIsAFlagSet = true; return this; } @Override public boolean getRFlag() { return this.bRFlag; } @Override public Builder setRFlag(boolean value) { this.bRFlag = value; this.bIsRFlagSet = true; return this; } @Override public boolean getSFlag() { return this.bSFlag; } @Override public Builder setSFlag(boolean value) { this.bSFlag = value; this.bIsSFlagSet = true; return this; } @Override public boolean getDFlag() { return this.bDFlag; } @Override public Builder setDFlag(boolean value) { this.bDFlag = value; this.bIsDFlagSet = true; return this; } @Override public Builder setOptionalTlv(LinkedList<PcepValueType> llOptionalTlv) { this.llOptionalTlv = llOptionalTlv; return this; } @Override public LinkedList<PcepValueType> getOptionalTlv() { return this.llOptionalTlv; } @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("PlspIDValue", iPlspId) .add("CFlag", bCFlag) .add("OFlag", yOFlag) .add("AFlag", bAFlag) .add("RFlag", bRFlag) .add("SFlag", bSFlag) .add("DFlag", bDFlag) .add("OptionalTlvList", llOptionalTlv) .toString(); } }