/* * 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.PcInitiatedLspRequest; import org.onosproject.pcepio.protocol.PcepAttribute; import org.onosproject.pcepio.protocol.PcepEndPointsObject; import org.onosproject.pcepio.protocol.PcepEroObject; import org.onosproject.pcepio.protocol.PcepInitiateMsg; import org.onosproject.pcepio.protocol.PcepLspObject; import org.onosproject.pcepio.protocol.PcepMessageReader; import org.onosproject.pcepio.protocol.PcepMessageWriter; import org.onosproject.pcepio.protocol.PcepSrpObject; import org.onosproject.pcepio.protocol.PcepType; import org.onosproject.pcepio.protocol.PcepVersion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.MoreObjects; /** * Provides PCEP initiate message. */ class PcepInitiateMsgVer1 implements PcepInitiateMsg { protected static final Logger log = LoggerFactory.getLogger(PcepInitiateMsgVer1.class); // Ref : PCE initiated tunnel setup draft-ietf-pce-pce-initiated-lsp-03, section 5.1 /* <PCInitiate Message> ::= <Common Header> * <PCE-initiated-lsp-list> * Where: * <PCE-initiated-lsp-list> ::= <PCE-initiated-lsp-request>[<PCE-initiated-lsp-list>] * <PCE-initiated-lsp-request> ::= (<PCE-initiated-lsp-instantiation>|<PCE-initiated-lsp-deletion>) * <PCE-initiated-lsp-instantiation> ::= <SRP> * <LSP> * <END-POINTS> * <ERO> * [<attribute-list>] * <PCE-initiated-lsp-deletion> ::= <SRP> * <LSP> */ static final byte PACKET_VERSION = 1; /* considering LspDelete Request PcInitiate msg will contain * common header * srp object * lsp object * so min length for this can be * PACKET_MINIMUM_LENGTH = CommonHeaderLen(4)+SrpObjectMinLen(12)+LspObjectMinLen(8) */ public static final short PACKET_MINIMUM_LENGTH = 24; public static final short MINIMUM_COMMON_HEADER_LENGTH = 4; public static final PcepType MSG_TYPE = PcepType.INITIATE; private LinkedList<PcInitiatedLspRequest> llPcInitiatedLspRequestList; public static final PcepInitiateMsgVer1.Reader READER = new Reader(); /** * Reader class for reading of Pcep initiate message from channel buffer. */ static class Reader implements PcepMessageReader<PcepInitiateMsg> { LinkedList<PcInitiatedLspRequest> llPcInitiatedLspRequestList; @Override public PcepInitiateMsg readFrom(ChannelBuffer cb) throws PcepParseException { if (cb.readableBytes() < PACKET_MINIMUM_LENGTH) { return null; } llPcInitiatedLspRequestList = new LinkedList<>(); byte version = cb.readByte(); version = (byte) (version >> PcepMessageVer1.SHIFT_FLAG); if (version != PACKET_VERSION) { throw new PcepParseException("Wrong version. Expected=PcepVersion.PCEP_1(1), received=" + version); } byte type = cb.readByte(); if (type != MSG_TYPE.getType()) { throw new PcepParseException("Wrong type. Expected=PcepType.INITIATE(12), recived=" + type); } short length = cb.readShort(); if (length < PACKET_MINIMUM_LENGTH) { throw new PcepParseException("Wrong length. Initiate message length expected to be >= " + PACKET_MINIMUM_LENGTH + ", but received=" + length); } log.debug("reading PcInitiate message of length " + length); // parse Start initiate/deletion list if (!parsePcInitiatedLspRequestList(cb)) { throw new PcepParseException("Parsing PCE-initiated-lsp-Request-list failed"); } return new PcepInitiateMsgVer1(llPcInitiatedLspRequestList); } /** * To parse PcInitiatedLspRequestList from PcInitiate Message. * * @param cb of type channel buffer * @return true if parsing PcInitiatedLspRequestList is success, false otherwise * @throws PcepParseException while parsing from channel buffer */ public boolean parsePcInitiatedLspRequestList(ChannelBuffer cb) throws PcepParseException { boolean isDelLspRequest = false; if (cb == null) { throw new PcepParseException("Channel buffer is empty"); } while (0 < cb.readableBytes()) { PcInitiatedLspRequest pceInitLspReq = new PcInitiatedLspRequestVer1(); //store SRP object PcepSrpObject srpObj; srpObj = PcepSrpObjectVer1.read(cb); pceInitLspReq.setSrpObject(srpObj); isDelLspRequest = srpObj.getRFlag(); //store LSP object PcepLspObject lspObj; lspObj = PcepLspObjectVer1.read(cb); pceInitLspReq.setLspObject(lspObj); /* if R bit will be set then pcInitiate msg will contain only LSp and SRP objects * so if R bit is not set then we should read for Ero and EndPoint objects also. */ if (!isDelLspRequest) { //store EndPoint object PcepEndPointsObject endPointObj; endPointObj = PcepEndPointsObjectVer1.read(cb); pceInitLspReq.setEndPointsObject(endPointObj); //store ERO object PcepEroObject eroObj; eroObj = PcepEroObjectVer1.read(cb); pceInitLspReq.setEroObject(eroObj); if (cb.readableBytes() > MINIMUM_COMMON_HEADER_LENGTH) { pceInitLspReq.setPcepAttribute(PcepAttributeVer1.read(cb)); } } llPcInitiatedLspRequestList.add(pceInitLspReq); } return true; } } /** * Constructor to initialize PcInitiatedLspRequest. * * @param llPcInitiatedLspRequestList list of PcInitiatedLspRequest */ PcepInitiateMsgVer1(LinkedList<PcInitiatedLspRequest> llPcInitiatedLspRequestList) { if (llPcInitiatedLspRequestList == null) { throw new NullPointerException("PcInitiatedLspRequestList cannot be null."); } this.llPcInitiatedLspRequestList = llPcInitiatedLspRequestList; } /** * Builder class for PCEP initiate message. */ static class Builder implements PcepInitiateMsg.Builder { // Pcep initiate message fields LinkedList<PcInitiatedLspRequest> llPcInitiatedLspRequestList; @Override public PcepVersion getVersion() { return PcepVersion.PCEP_1; } @Override public PcepType getType() { return PcepType.INITIATE; } @Override public PcepInitiateMsg build() { return new PcepInitiateMsgVer1(this.llPcInitiatedLspRequestList); } @Override public LinkedList<PcInitiatedLspRequest> getPcInitiatedLspRequestList() { return this.llPcInitiatedLspRequestList; } @Override public Builder setPcInitiatedLspRequestList(LinkedList<PcInitiatedLspRequest> ll) { this.llPcInitiatedLspRequestList = ll; return this; } } @Override public void writeTo(ChannelBuffer cb) throws PcepParseException { WRITER.write(cb, this); } static final Writer WRITER = new Writer(); /** * Writer class for writing pcep initiate message to channel buffer. */ static class Writer implements PcepMessageWriter<PcepInitiateMsgVer1> { @Override public void write(ChannelBuffer cb, PcepInitiateMsgVer1 message) throws PcepParseException { boolean isDelLspRequest = false; int startIndex = cb.writerIndex(); // first 3 bits set to version cb.writeByte((byte) (PACKET_VERSION << PcepMessageVer1.SHIFT_FLAG)); // message type 0xC cb.writeByte(MSG_TYPE.getType()); // length is length of variable message, will be updated at the end // Store the position of message // length in buffer int msgLenIndex = cb.writerIndex(); cb.writeShort(0); ListIterator<PcInitiatedLspRequest> listIterator = message.llPcInitiatedLspRequestList.listIterator(); while (listIterator.hasNext()) { PcInitiatedLspRequest listReq = listIterator.next(); //Srp Object is mandatory PcepSrpObject srpObj = listReq.getSrpObject(); if (srpObj != null) { isDelLspRequest = srpObj.getRFlag(); srpObj.write(cb); } else { throw new PcepParseException("SRP Object is mandatory for PcInitiate message."); } //LSP Object is mandatory PcepLspObject lspObj = listReq.getLspObject(); if (lspObj != null) { lspObj.write(cb); } else { throw new PcepParseException("LSP Object is mandatory for PcInitiate message."); } /* if R bit will be set then pcInitiate msg will contain only LSp and SRP objects * so if R bit is not set then we should read for Ero and EndPoint objects also. */ if (!isDelLspRequest) { //EndPoints object is mandatory PcepEndPointsObject endPointObj = listReq.getEndPointsObject(); if (endPointObj != null) { endPointObj.write(cb); } else { throw new PcepParseException("End points Object is mandatory for PcInitiate message."); } //Ero object is mandatory PcepEroObject eroObj = listReq.getEroObject(); if (eroObj != null) { eroObj.write(cb); } else { throw new PcepParseException("ERO Object is mandatory for PcInitiate message."); } //PcepAttribute is optional PcepAttribute pcepAttribute = listReq.getPcepAttribute(); if (pcepAttribute != null) { pcepAttribute.write(cb); } } } // PCInitiate message length field int length = cb.writerIndex() - startIndex; cb.setShort(msgLenIndex, (short) length); } } @Override public PcepVersion getVersion() { return PcepVersion.PCEP_1; } @Override public PcepType getType() { return MSG_TYPE; } @Override public LinkedList<PcInitiatedLspRequest> getPcInitiatedLspRequestList() { return this.llPcInitiatedLspRequestList; } @Override public void setPcInitiatedLspRequestList(LinkedList<PcInitiatedLspRequest> ll) { this.llPcInitiatedLspRequestList = ll; } @Override public String toString() { return MoreObjects.toStringHelper(getClass()) .add("PcInitiaitedLspRequestList", llPcInitiatedLspRequestList) .toString(); } }