blob: fcf3421ccdeada79e87aa141801d8f10b0b39d66 [file] [log] [blame]
/*
* Copyright 2015-present Open Networking Foundation
*
* 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.PcepCloseMsg;
import org.onosproject.pcepio.protocol.PcepMessageReader;
import org.onosproject.pcepio.protocol.PcepMessageWriter;
import org.onosproject.pcepio.protocol.PcepType;
import org.onosproject.pcepio.protocol.PcepVersion;
import org.onosproject.pcepio.types.PcepObjectHeader;
import org.onosproject.pcepio.types.PcepValueType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.MoreObjects;
/**
* Provides PCEP Close Message.
*/
class PcepCloseMsgVer1 implements PcepCloseMsg {
/*
* RFC : 5440 , section : 6.8
* <Close Message> ::= <Common Header> <CLOSE>
*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Ver | Flags | Message-Type | Message-Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Object-Class | OT |Res|P|I| Object Length (bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reserved | Flags | Reason |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
// Optional TLVs //
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
private static final Logger log = LoggerFactory.getLogger(PcepCloseMsgVer1.class);
// Pcep version: 1
public static final byte PACKET_VERSION = 1;
public static final int PACKET_MINIMUM_LENGTH = 12;
public static final PcepType MSG_TYPE = PcepType.CLOSE;
public static final byte CLOSE_OBJ_TYPE = 1;
public static final byte CLOSE_OBJ_CLASS = 15;
public static final byte CLOSE_OBJECT_VERSION = 1;
public static final byte DEFAULT_REASON = 1; // Default reason to close
public static final short CLOSE_OBJ_MINIMUM_LENGTH = 8;
public static final int SHIFT_FLAG = 5;
static final PcepObjectHeader DEFAULT_CLOSE_HEADER = new PcepObjectHeader(CLOSE_OBJ_CLASS, CLOSE_OBJ_TYPE,
PcepObjectHeader.REQ_OBJ_OPTIONAL_PROCESS, PcepObjectHeader.RSP_OBJ_PROCESSED, CLOSE_OBJ_MINIMUM_LENGTH);
private final PcepObjectHeader closeObjHeader;
private byte yReason;
private LinkedList<PcepValueType> llOptionalTlv;
public static final PcepCloseMsgVer1.Reader READER = new Reader();
/**
* Reader class for reading close message for channel buffer.
*/
static class Reader implements PcepMessageReader<PcepCloseMsg> {
PcepObjectHeader closeObjHeader;
byte yReason;
// Optional TLV
private LinkedList<PcepValueType> llOptionalTlv;
@Override
public PcepCloseMsg readFrom(ChannelBuffer cb) throws PcepParseException {
if (cb.readableBytes() < PACKET_MINIMUM_LENGTH) {
throw new PcepParseException("Packet size is less than the minimum length.");
}
// fixed value property version == 1
byte version = cb.readByte();
version = (byte) (version >> SHIFT_FLAG);
if (version != PACKET_VERSION) {
throw new PcepParseException("Wrong version. Expected=PcepVersion.PCEP_1(1), got=" + version);
}
// fixed value property type == 7
byte type = cb.readByte();
if (type != MSG_TYPE.getType()) {
throw new PcepParseException("Wrong type. Expected=PcepType.CLOSE(7), got=" + type);
}
short length = cb.readShort();
if (length < PACKET_MINIMUM_LENGTH) {
throw new PcepParseException("Wrong length. Expected to be >= " + PACKET_MINIMUM_LENGTH + ", was: "
+ length);
}
closeObjHeader = PcepObjectHeader.read(cb);
// Reserved
cb.readShort();
// Flags
cb.readByte();
// Reason
yReason = cb.readByte();
// parse optional TLV
llOptionalTlv = parseOptionalTlv(cb);
return new PcepCloseMsgVer1(closeObjHeader, yReason, llOptionalTlv);
}
}
/**
* Parse the list of Optional Tlvs.
*
* @param cb channel buffer
* @return list of Optional Tlvs
* @throws PcepParseException when fails to parse optional tlvs
*/
public static LinkedList<PcepValueType> parseOptionalTlv(ChannelBuffer cb) throws PcepParseException {
LinkedList<PcepValueType> llOptionalTlv = new LinkedList<>();
/*
rfc 5440:
Optional TLVs may be included within the CLOSE object body. The
specification of such TLVs is outside the scope of this document.
*/
return llOptionalTlv;
}
/**
* constructor to initialize PCEP close Message with all the parameters.
*
* @param closeObjHeader object header for close message
* @param yReason reason for closing the channel
* @param llOptionalTlv list of optional tlvs
*/
PcepCloseMsgVer1(PcepObjectHeader closeObjHeader, byte yReason, LinkedList<PcepValueType> llOptionalTlv) {
this.closeObjHeader = closeObjHeader;
this.yReason = yReason;
this.llOptionalTlv = llOptionalTlv;
}
/**
* Builder class for PCEP close message.
*/
static class Builder implements PcepCloseMsg.Builder {
// PCEP Close message fields
private boolean bIsHeaderSet = false;
private PcepObjectHeader closeObjHeader;
private boolean bIsReasonSet = false;
private byte yReason;
private LinkedList<PcepValueType> llOptionalTlv = new LinkedList<>();
private boolean bIsPFlagSet = false;
private boolean bPFlag;
private boolean bIsIFlagSet = false;
private boolean bIFlag;
@Override
public PcepVersion getVersion() {
return PcepVersion.PCEP_1;
}
@Override
public PcepType getType() {
return PcepType.CLOSE;
}
@Override
public PcepCloseMsg build() {
PcepObjectHeader closeObjHeader = this.bIsHeaderSet ? this.closeObjHeader : DEFAULT_CLOSE_HEADER;
byte yReason = this.bIsReasonSet ? this.yReason : DEFAULT_REASON;
if (bIsPFlagSet) {
closeObjHeader.setPFlag(bPFlag);
}
if (bIsIFlagSet) {
closeObjHeader.setIFlag(bIFlag);
}
return new PcepCloseMsgVer1(closeObjHeader, yReason, this.llOptionalTlv);
}
@Override
public PcepObjectHeader getCloseObjHeader() {
return this.closeObjHeader;
}
@Override
public Builder setCloseObjHeader(PcepObjectHeader obj) {
this.closeObjHeader = obj;
this.bIsHeaderSet = true;
return this;
}
@Override
public byte getReason() {
return this.yReason;
}
@Override
public Builder setReason(byte value) {
this.yReason = value;
this.bIsReasonSet = 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 void writeTo(ChannelBuffer cb) throws PcepParseException {
WRITER.write(cb, this);
}
static final Writer WRITER = new Writer();
/**
* Writer class for writing close message to channel buffer.
*/
static class Writer implements PcepMessageWriter<PcepCloseMsgVer1> {
@Override
public void write(ChannelBuffer cb, PcepCloseMsgVer1 message) throws PcepParseException {
int startIndex = cb.writerIndex();
// first 3 bits set to version
cb.writeByte((byte) (PACKET_VERSION << SHIFT_FLAG));
// message type
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((short) 0);
int objStartIndex = cb.writerIndex();
int objLenIndex = message.closeObjHeader.write(cb);
if (objLenIndex <= 0) {
throw new PcepParseException("Failed to write Close object header.");
}
// first 3 bits set to version
cb.writeShort(0); // Reserved
cb.writeByte(0); // Flags
cb.writeByte(message.yReason);
// Pack optional TLV
packOptionalTlv(cb, message);
int length = cb.writerIndex() - objStartIndex;
cb.setShort(objLenIndex, (short) length);
// will be helpful during print().
message.closeObjHeader.setObjLen((short) length);
// As per RFC the length of object should be
// multiples of 4
int pad = length % 4;
if (pad != 0) {
pad = 4 - pad;
for (int i = 0; i < pad; i++) {
cb.writeByte((byte) 0);
}
length = length + pad;
}
// update message length field
length = cb.writerIndex() - startIndex;
cb.setShort(msgLenIndex, (short) length);
}
public void packOptionalTlv(ChannelBuffer cb, PcepCloseMsgVer1 message) {
LinkedList<PcepValueType> llOptionalTlv = message.llOptionalTlv;
ListIterator<PcepValueType> listIterator = llOptionalTlv.listIterator();
while (listIterator.hasNext()) {
listIterator.next().write(cb);
}
}
}
@Override
public PcepVersion getVersion() {
return PcepVersion.PCEP_1;
}
@Override
public PcepType getType() {
return MSG_TYPE;
}
@Override
public byte getReason() {
return this.yReason;
}
@Override
public void setReason(byte value) {
this.yReason = value;
}
@Override
public LinkedList<PcepValueType> getOptionalTlv() {
return this.llOptionalTlv;
}
@Override
public void setOptionalTlv(LinkedList<PcepValueType> llOptionalTlv) {
this.llOptionalTlv = llOptionalTlv;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("closeObjectHeader", closeObjHeader).add("Reason", yReason)
.add("OptionalTlvlist", llOptionalTlv).toString();
}
}