| /* |
| * Copyright 2016-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.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(); |
| } |
| } |