blob: d90c848acaa0ee6955fa9dc0e1a187f803c7c5f8 [file] [log] [blame]
/*
* 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.List;
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.PcepLSObject;
import org.onosproject.pcepio.types.LocalNodeDescriptorsTlv;
import org.onosproject.pcepio.types.PcepObjectHeader;
import org.onosproject.pcepio.types.PcepValueType;
import org.onosproject.pcepio.types.RemoteNodeDescriptorsTlv;
import org.onosproject.pcepio.types.RoutingUniverseTlv;
import org.onosproject.pcepio.types.LinkAttributesTlv;
import org.onosproject.pcepio.types.LinkDescriptorsTlv;
import org.onosproject.pcepio.types.NodeAttributesTlv;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.MoreObjects;
/**
* Provides PCEP LS (link-state) object.
*/
public class PcepLSObjectVer1 implements PcepLSObject {
/*
*
reference: draft-dhodylee-pce-pcep-ls-01, section 9.2.
Two Object-Type values are defined for the LS object:
o LS Node: LS Object-Type is 1.
o LS Link: LS Object-Type is 2.
o LS IPv4 Topology Prefix: LS Object-Type is 3.
o LS IPv6 Topology Prefix: LS Object-Type is 4.
The format of the LS 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|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| LS-ID |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// TLVs //
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
protected static final Logger log = LoggerFactory.getLogger(PcepLSObjectVer1.class);
public static final byte LS_OBJ_TYPE_NODE_VALUE = 1;
public static final byte LS_OBJ_TYPE_LINK_VALUE = 2;
public static final byte LS_OBJ_CLASS = (byte) 224;
public static final byte LS_OBJECT_VERSION = 1;
// LS_OBJ_MINIMUM_LENGTH = LSObjectHeaderLen(4) + LSObjectLen(8)
public static final short LS_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_LS_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_LS_OBJECT_HEADER = new PcepObjectHeader(LS_OBJ_CLASS,
LS_OBJ_TYPE_NODE_VALUE, PcepObjectHeader.REQ_OBJ_OPTIONAL_PROCESS, PcepObjectHeader.RSP_OBJ_PROCESSED,
LS_OBJ_MINIMUM_LENGTH);
private PcepObjectHeader lsObjHeader;
private byte protocolId;
// 2-flags
private boolean removeFlag;
private boolean syncFlag;
private long lsId; //link-state identifier
// Optional TLV
private List<PcepValueType> optionalTlvList;
/**
* Constructor to initialize variables.
*
* @param lsObjHeader LS Object header
* @param protocolId Protocol-ID
* @param removeFlag R-flag
* @param syncFlag S-flag
* @param lsId LS-ID
* @param optionalTlvList linked list of Optional TLV
*/
public PcepLSObjectVer1(PcepObjectHeader lsObjHeader, byte protocolId, boolean removeFlag,
boolean syncFlag, long lsId, List<PcepValueType> optionalTlvList) {
this.lsObjHeader = lsObjHeader;
this.protocolId = protocolId;
this.removeFlag = removeFlag;
this.syncFlag = syncFlag;
this.lsId = lsId;
this.optionalTlvList = optionalTlvList;
}
@Override
public PcepObjectHeader getLSObjHeader() {
return this.lsObjHeader;
}
@Override
public void setLSObjHeader(PcepObjectHeader obj) {
this.lsObjHeader = obj;
}
@Override
public byte getProtocolId() {
return this.protocolId;
}
@Override
public void setProtocolId(byte protId) {
this.protocolId = protId;
}
@Override
public boolean getRemoveFlag() {
return this.removeFlag;
}
@Override
public void setRemoveFlag(boolean removeFlag) {
this.removeFlag = removeFlag;
}
@Override
public boolean getSyncFlag() {
return this.syncFlag;
}
@Override
public void setSyncFlag(boolean syncFlag) {
this.syncFlag = syncFlag;
}
@Override
public long getLSId() {
return this.lsId;
}
@Override
public void setLSId(long lsId) {
this.lsId = lsId;
}
@Override
public List<PcepValueType> getOptionalTlv() {
return this.optionalTlvList;
}
@Override
public void setOptionalTlv(List<PcepValueType> optionalTlvList) {
this.optionalTlvList = optionalTlvList;
}
/**
* Reads from the channel buffer and returns Object of PcepLSObject.
*
* @param cb of type channel buffer
* @return Object of PcepLSObject
* @throws PcepParseException if mandatory fields are missing
*/
public static PcepLSObject read(ChannelBuffer cb) throws PcepParseException {
log.debug("read");
PcepObjectHeader lsObjHeader;
byte protocolId;
// 2-flags
boolean removeFlag;
boolean syncFlag;
long lsId;
List<PcepValueType> optionalTlvList;
lsObjHeader = PcepObjectHeader.read(cb);
//take only LSObject buffer.
ChannelBuffer tempCb = cb.readBytes(lsObjHeader.getObjLen() - OBJECT_HEADER_LENGTH);
protocolId = tempCb.readByte();
//ignore first two bytes of Flags
tempCb.readShort();
Integer iTemp = (int) tempCb.readByte(); //read 3rd byte Flag
syncFlag = (iTemp & FLAG_SET_S_FLAG) == FLAG_SET_S_FLAG;
removeFlag = (iTemp & FLAG_SET_R_FLAG) == FLAG_SET_R_FLAG;
lsId = tempCb.readLong();
// parse optional TLV
optionalTlvList = parseOptionalTlv(tempCb);
return new PcepLSObjectVer1(lsObjHeader, protocolId, removeFlag, syncFlag, lsId, optionalTlvList);
}
@Override
public int write(ChannelBuffer cb) throws PcepParseException {
//write Object header
int objStartIndex = cb.writerIndex();
int objLenIndex = lsObjHeader.write(cb);
if (objLenIndex <= 0) {
throw new PcepParseException("ObjectLength Index is " + objLenIndex);
}
//write Protocol ID
cb.writeByte(this.protocolId);
//write Flag
cb.writeShort(0);
byte bTemp = 0;
if (syncFlag) {
bTemp = FLAG_SET_S_FLAG;
}
if (removeFlag) {
bTemp = (byte) (bTemp | FLAG_SET_R_FLAG);
}
cb.writeByte(bTemp);
//write LSId
cb.writeLong(lsId);
// Add optional TLV
packOptionalTlv(cb);
//Update object length now
int length = cb.writerIndex() - objStartIndex;
//will be helpful during print().
lsObjHeader.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 List<PcepValueType> parseOptionalTlv(ChannelBuffer cb) throws PcepParseException {
List<PcepValueType> llOutOptionalTlv;
llOutOptionalTlv = new LinkedList<>();
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 LocalNodeDescriptorsTlv.TYPE:
tlv = LocalNodeDescriptorsTlv.read(cb, hLength);
break;
case RemoteNodeDescriptorsTlv.TYPE:
tlv = RemoteNodeDescriptorsTlv.read(cb, hLength);
break;
case LinkDescriptorsTlv.TYPE:
tlv = LinkDescriptorsTlv.read(cb, hLength);
break;
case NodeAttributesTlv.TYPE:
tlv = NodeAttributesTlv.read(cb, hLength);
break;
case LinkAttributesTlv.TYPE:
tlv = LinkAttributesTlv.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 = optionalTlvList.listIterator();
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();
}
/**
* Builder class for PCEP LS (link-state) object.
*/
public static class Builder implements PcepLSObject.Builder {
private boolean isHeaderSet = false;
private boolean isProtocolIdSet = false;
private boolean isRemoveFlagSet = false;
private boolean isSyncFlagSet = false;
private boolean isLSIdSet = false;
private PcepObjectHeader lsObjHeader;
private byte protocolId;
private boolean removeFlag;
private boolean syncFlag;
private long lsId;
private List<PcepValueType> optionalTlvList = new LinkedList<>();
private boolean isProcRuleFlagSet = false;
private boolean procRuleFlag; //Processing rule flag
private boolean isIgnoreFlagSet = false;
private boolean ignoreFlag;
@Override
public PcepLSObject build() {
PcepObjectHeader lsObjHeader = this.isHeaderSet ? this.lsObjHeader : DEFAULT_LS_OBJECT_HEADER;
byte protocolId = this.isProtocolIdSet ? this.protocolId : DEFAULT_PROTOCOL_ID;
boolean removeFlag = this.isRemoveFlagSet ? this.removeFlag : DEFAULT_R_FLAG;
boolean syncFlag = this.isSyncFlagSet ? this.syncFlag : DEFAULT_S_FLAG;
long lsId = this.isLSIdSet ? this.lsId : DEFAULT_LS_ID;
if (isProcRuleFlagSet) {
lsObjHeader.setPFlag(procRuleFlag);
}
if (isIgnoreFlagSet) {
lsObjHeader.setIFlag(ignoreFlag);
}
return new PcepLSObjectVer1(lsObjHeader, protocolId, removeFlag, syncFlag, lsId, optionalTlvList);
}
@Override
public PcepObjectHeader getLSObjHeader() {
return this.lsObjHeader;
}
@Override
public Builder setLSObjHeader(PcepObjectHeader obj) {
this.lsObjHeader = obj;
this.isHeaderSet = true;
return this;
}
@Override
public byte getProtocolId() {
return this.protocolId;
}
@Override
public Builder setProtocolId(byte protId) {
this.protocolId = protId;
this.isProtocolIdSet = true;
return this;
}
@Override
public boolean getRemoveFlag() {
return this.removeFlag;
}
@Override
public Builder setRemoveFlag(boolean removeFlag) {
this.removeFlag = removeFlag;
this.isRemoveFlagSet = true;
return this;
}
@Override
public boolean getSyncFlag() {
return this.syncFlag;
}
@Override
public Builder setSyncFlag(boolean syncFlag) {
this.syncFlag = syncFlag;
this.isSyncFlagSet = true;
return this;
}
@Override
public long getLSId() {
return this.lsId;
}
@Override
public Builder setLSId(long lsId) {
this.lsId = lsId;
this.isLSIdSet = true;
return this;
}
@Override
public List<PcepValueType> getOptionalTlv() {
return this.optionalTlvList;
}
@Override
public Builder setOptionalTlv(List<PcepValueType> optionalTlvList) {
this.optionalTlvList = optionalTlvList;
return this;
}
@Override
public Builder setPFlag(boolean value) {
this.procRuleFlag = value;
this.isProcRuleFlagSet = true;
return this;
}
@Override
public Builder setIFlag(boolean value) {
this.ignoreFlag = value;
this.isIgnoreFlagSet = true;
return this;
}
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass()).omitNullValues()
.add("ObjectHeader", lsObjHeader)
.add("ProtocolId", protocolId)
.add("RFlag", (removeFlag) ? 1 : 0)
.add("SFlag", (syncFlag) ? 1 : 0)
.add("LsId", lsId)
.add("OptionalTlv", optionalTlvList).toString();
}
}