/* * 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.LinkedList; import java.util.ListIterator; import org.jboss.netty.buffer.ChannelBuffer; import org.onosproject.pcepio.exceptions.PcepParseException; import org.onosproject.pcepio.protocol.PcepLabelObject; import org.onosproject.pcepio.types.NexthopIPv4addressTlv; import org.onosproject.pcepio.types.NexthopIPv6addressTlv; import org.onosproject.pcepio.types.NexthopUnnumberedIPv4IDTlv; 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 label object. */ public class PcepLabelObjectVer1 implements PcepLabelObject { /* * ref : draft-zhao-pce-pcep-extension-for-pce-controller-01 , section : 7.4. 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reserved | Flags |O| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Label | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | // Optional TLV // | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ The LABEL Object format */ protected static final Logger log = LoggerFactory.getLogger(PcepLspObjectVer1.class); public static final byte LABEL_OBJ_TYPE = 1; public static final byte LABEL_OBJ_CLASS = 35; //TBD : to be defined public static final byte LABEL_OBJECT_VERSION = 1; public static final byte OBJECT_HEADER_LENGTH = 4; public static final boolean DEFAULT_OFLAG = false; // LSP_OBJ_MINIMUM_LENGTH = CommonHeaderLen(4)+ LspObjectHeaderLen(8) public static final short LABEL_OBJ_MINIMUM_LENGTH = 12; public static final int OFLAG_SET = 1; public static final int OFLAG_RESET = 0; public static final int MINIMUM_COMMON_HEADER_LENGTH = 4; static final PcepObjectHeader DEFAULT_LABEL_OBJECT_HEADER = new PcepObjectHeader(LABEL_OBJ_CLASS, LABEL_OBJ_TYPE, PcepObjectHeader.REQ_OBJ_OPTIONAL_PROCESS, PcepObjectHeader.RSP_OBJ_PROCESSED, LABEL_OBJ_MINIMUM_LENGTH); private PcepObjectHeader labelObjHeader; private boolean bOFlag; private int label; // Optional TLV private LinkedList llOptionalTlv; /** * Constructor to initialize parameters for PCEP label object. * * @param labelObjHeader label object header * @param bOFlag O flag * @param label label * @param llOptionalTlv list of optional tlvs */ public PcepLabelObjectVer1(PcepObjectHeader labelObjHeader, boolean bOFlag, int label, LinkedList llOptionalTlv) { this.labelObjHeader = labelObjHeader; this.bOFlag = bOFlag; this.label = label; this.llOptionalTlv = llOptionalTlv; } @Override public LinkedList getOptionalTlv() { return this.llOptionalTlv; } @Override public void setOptionalTlv(LinkedList llOptionalTlv) { this.llOptionalTlv = llOptionalTlv; } @Override public boolean getOFlag() { return this.bOFlag; } @Override public void setOFlag(boolean value) { this.bOFlag = value; } @Override public int getLabel() { return this.label; } @Override public void setLabel(int value) { this.label = value; } /** * Reads form channel buffer and returns objects of PcepLabelObject. * * @param cb of type channel buffer * @return objects of PcepLabelObject * @throws PcepParseException when fails to read from channel buffer */ public static PcepLabelObject read(ChannelBuffer cb) throws PcepParseException { PcepObjectHeader labelObjHeader; boolean bOFlag; int label; // Optional TLV LinkedList llOptionalTlv = new LinkedList<>(); labelObjHeader = PcepObjectHeader.read(cb); //take only LspObject buffer. ChannelBuffer tempCb = cb.readBytes(labelObjHeader.getObjLen() - OBJECT_HEADER_LENGTH); int iTemp = tempCb.readInt(); bOFlag = (iTemp & (byte) 0x01) == 1; label = tempCb.readInt(); // parse optional TLV llOptionalTlv = parseOptionalTlv(tempCb); return new PcepLabelObjectVer1(labelObjHeader, bOFlag, label, llOptionalTlv); } @Override public int write(ChannelBuffer cb) throws PcepParseException { //write Object header int objStartIndex = cb.writerIndex(); int objLenIndex = labelObjHeader.write(cb); if (objLenIndex <= 0) { throw new PcepParseException(" ObjectLength Index is " + objLenIndex); } byte oFlag; oFlag = (byte) ((bOFlag) ? OFLAG_SET : OFLAG_RESET); cb.writeInt(oFlag); cb.writeInt(label); // Add optional TLV packOptionalTlv(cb); //Update object length now int length = cb.writerIndex() - objStartIndex; //will be helpful during print(). labelObjHeader.setObjLen((short) length); cb.setShort(objLenIndex, (short) length); return cb.writerIndex(); } /** * Returns list of optional tlvs. * * @param cb of type channel buffer * @return list of optional tlvs. * @throws PcepParseException when fails to parse list of optional tlvs */ protected static LinkedList parseOptionalTlv(ChannelBuffer cb) throws PcepParseException { LinkedList llOutOptionalTlv = new LinkedList<>(); while (MINIMUM_COMMON_HEADER_LENGTH <= cb.readableBytes()) { PcepValueType tlv; short hType = cb.readShort(); short hLength = cb.readShort(); int iValue = 0; switch (hType) { case NexthopIPv4addressTlv.TYPE: iValue = cb.readInt(); tlv = new NexthopIPv4addressTlv(iValue); break; case NexthopIPv6addressTlv.TYPE: byte[] ipv6Value = new byte[NexthopIPv6addressTlv.VALUE_LENGTH]; cb.readBytes(ipv6Value, 0, NexthopIPv6addressTlv.VALUE_LENGTH); tlv = new NexthopIPv6addressTlv(ipv6Value); break; case NexthopUnnumberedIPv4IDTlv.TYPE: tlv = NexthopUnnumberedIPv4IDTlv.read(cb); 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 channel buffer. * @return writer index */ protected int packOptionalTlv(ChannelBuffer cb) { ListIterator listIterator = llOptionalTlv.listIterator(); while (listIterator.hasNext()) { PcepValueType tlv = listIterator.next(); if (tlv == null) { log.debug("tlv is null from OptionalTlv list"); continue; } tlv.write(cb); } return cb.writerIndex(); } /** * Builder class for PCEP label object. */ public static class Builder implements PcepLabelObject.Builder { private boolean bIsHeaderSet = false; private boolean bIsOFlagSet = false; private boolean bIsLabelSet = false; private PcepObjectHeader labelObjHeader; private boolean bOFlag; private int label; LinkedList llOptionalTlv = new LinkedList<>(); private boolean bIsPFlagSet = false; private boolean bPFlag; private boolean bIsIFlagSet = false; private boolean bIFlag; @Override public PcepLabelObject build() throws PcepParseException { PcepObjectHeader labelObjHeader = this.bIsHeaderSet ? this.labelObjHeader : DEFAULT_LABEL_OBJECT_HEADER; boolean bOFlag = this.bIsOFlagSet ? this.bOFlag : DEFAULT_OFLAG; if (!this.bIsLabelSet) { throw new PcepParseException(" Label NOT Set while building PcepLabelObject."); } if (bIsPFlagSet) { labelObjHeader.setPFlag(bPFlag); } if (bIsIFlagSet) { labelObjHeader.setIFlag(bIFlag); } return new PcepLabelObjectVer1(labelObjHeader, bOFlag, this.label, this.llOptionalTlv); } @Override public PcepObjectHeader getLabelObjHeader() { return this.labelObjHeader; } @Override public Builder setLabelObjHeader(PcepObjectHeader obj) { this.labelObjHeader = obj; this.bIsHeaderSet = true; return this; } @Override public boolean getOFlag() { return this.bOFlag; } @Override public Builder setOFlag(boolean value) { this.bOFlag = value; this.bIsOFlagSet = true; return this; } @Override public int getLabel() { return this.label; } @Override public Builder setLabel(int value) { this.label = value; this.bIsLabelSet = true; return this; } @Override public LinkedList getOptionalTlv() { return this.llOptionalTlv; } @Override public Builder setOptionalTlv(LinkedList llOptionalTlv) { this.llOptionalTlv = llOptionalTlv; return this; } @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("OFlag", bOFlag) .add("label", label) .add("OptionalTlvList", llOptionalTlv) .toString(); } }