All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.onosproject.pcepio.protocol.ver1.PcepEroObjectVer1 Maven / Gradle / Ivy

There is a newer version: 2.4.0
Show newest version
/*
 * 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.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Objects;

import org.jboss.netty.buffer.ChannelBuffer;
import org.onosproject.pcepio.exceptions.PcepParseException;
import org.onosproject.pcepio.protocol.PcepEroObject;
import org.onosproject.pcepio.types.AutonomousSystemNumberSubObject;
import org.onosproject.pcepio.types.IPv4SubObject;
import org.onosproject.pcepio.types.IPv6SubObject;
import org.onosproject.pcepio.types.PathKeySubObject;
import org.onosproject.pcepio.types.PcepErrorDetailInfo;
import org.onosproject.pcepio.types.PcepObjectHeader;
import org.onosproject.pcepio.types.PcepValueType;
import org.onosproject.pcepio.types.SrEroSubObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.MoreObjects;

/**
 * Provides PCEP Ero Object.
 */
public class PcepEroObjectVer1 implements PcepEroObject {
    /*
     * rfc3209
      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
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     | Object-Class  |   OT  |Res|P|I|   Object Length (bytes)       |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                                                               |
     //                        (Subobjects)                          //
     |                                                               |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

     If a Path message contains multiple EXPLICIT_ROUTE objects, only the
     first object is meaningful.  Subsequent EXPLICIT_ROUTE objects MAY be
     ignored and SHOULD NOT be propagated.

     In current implementation, only strict hops are supported. So,
     empty ERO with no sub-objects is considered illegal.

     Subobjects:
      0                   1
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+
     |L|    Type     |     Length    | (Subobject contents)          |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+

      L

         The L bit is an attribute of the subobject.  The L bit is set
         if the subobject represents a loose hop in the explicit route.
         If the bit is not set, the subobject represents a strict hop in
         the explicit route.

      Type

         The Type indicates the type of contents of the subobject.


      Subobject 1: IPv4 address

      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
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |L|    Type     |     Length    | IPv4 address (4 bytes)        |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     | IPv4 address (continued)      | Prefix Length |      Resvd    |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

     Subobject 2:  IPv6 Prefix

      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
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |L|    Type     |     Length    | IPv6 address (16 bytes)       |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     | IPv6 address (continued)                                      |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     | IPv6 address (continued)                                      |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     | IPv6 address (continued)                                      |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     | IPv6 address (continued)      | Prefix Length |      Resvd    |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

     Subobject 3:  Autonomous System Number

     The contents of an Autonomous System (AS) number subobject are a 2-
     octet AS number.  The abstract node represented by this subobject is
     the set of nodes belonging to the autonomous system.

     The length of the AS number subobject is 4 octets.

     Subobject 4: PATH_KEY_32_BIT_SUB_OBJ_TYPE:

      Pathkey subobject(RFC 5520):
      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
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |L|    Type     |     Length    |           Path-Key            |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                         PCE ID (4 bytes)                      |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

     Subobject 5: SR_ERO_SUB_OBJ_TYPE:

       SR-ERO subobject: (draft-ietf-pce-segment-routing-00)
      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
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |L|    Type     |     Length    |  ST   |     Flags     |F|S|C|M|
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                              SID                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     //                        NAI (variable)                       //
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     */

    private static final Logger log = LoggerFactory.getLogger(PcepEroObjectVer1.class);

    public static final byte ERO_OBJ_TYPE = 1;
    public static final byte ERO_OBJ_CLASS = 7;
    public static final byte ERO_OBJECT_VERSION = 1;
    public static final short ERO_OBJ_MINIMUM_LENGTH = 12;
    public static final byte IPV4_TYPE = 1;
    public static final byte PATH_KEY_32_BIT_SUB_OBJ_TYPE = 64;
    public static final int LABEL_SUB_OBJ_TYPE = 3;
    public static final int SR_ERO_SUB_OBJ_TYPE = 96;
    public static final int OBJECT_HEADER_LENGTH = 4;
    public static final int TYPE_SHIFT_VALUE = 0x7F;

    public static final PcepObjectHeader DEFAULT_ERO_OBJECT_HEADER = new PcepObjectHeader(ERO_OBJ_CLASS, ERO_OBJ_TYPE,
            PcepObjectHeader.REQ_OBJ_OPTIONAL_PROCESS, PcepObjectHeader.RSP_OBJ_PROCESSED, ERO_OBJ_MINIMUM_LENGTH);

    private PcepObjectHeader eroObjHeader;
    private LinkedList subObjectList = new LinkedList<>();

    /**
     * reset variables.
     */
    public PcepEroObjectVer1() {
        this.eroObjHeader = null;
        this.subObjectList = null;
    }

    /**
     * Constructor to initialize parameters of ERO object.
     *
     * @param eroObjHeader ERO object header
     * @param subObjectList list of sub objects.
     */
    public PcepEroObjectVer1(PcepObjectHeader eroObjHeader, LinkedList subObjectList) {

        this.eroObjHeader = eroObjHeader;
        this.subObjectList = subObjectList;
    }

    /**
     * Returns ERO object header.
     *
     * @return eroObjHeader ERO object header
     */
    public PcepObjectHeader getEroObjHeader() {
        return this.eroObjHeader;
    }

    /**
     * Sets Object Header.
     *
     * @param obj ERO object header
     */
    public void setEroObjHeader(PcepObjectHeader obj) {
        this.eroObjHeader = obj;
    }

    @Override
    public LinkedList getSubObjects() {
        return this.subObjectList;
    }

    @Override
    public void setSubObjects(LinkedList subObjectList) {
        this.subObjectList = subObjectList;
    }

    /**
     * Reads from channel buffer and returns object of PcepEroObject.
     *
     * @param cb channel buffer.
     * @return  object of PcepEroObject
     * @throws PcepParseException when ERO object is not present in channel buffer
     */
    public static PcepEroObject read(ChannelBuffer cb) throws PcepParseException {

        PcepObjectHeader eroObjHeader;
        LinkedList subObjectList = new LinkedList<>();

        eroObjHeader = PcepObjectHeader.read(cb);

        if (eroObjHeader.getObjClass() != PcepEroObjectVer1.ERO_OBJ_CLASS) {
            log.debug("ErrorType:" + PcepErrorDetailInfo.ERROR_TYPE_6 + " ErrorValue:"
                    + PcepErrorDetailInfo.ERROR_VALUE_9);
            throw new PcepParseException(PcepErrorDetailInfo.ERROR_TYPE_6, PcepErrorDetailInfo.ERROR_VALUE_9);
        }

        if (eroObjHeader.getObjLen() > OBJECT_HEADER_LENGTH) {
            ChannelBuffer tempCb = cb.readBytes(eroObjHeader.getObjLen() - OBJECT_HEADER_LENGTH);
            subObjectList = parseSubObjects(tempCb);
        }
        return new PcepEroObjectVer1(eroObjHeader, subObjectList);
    }

    /**
     * Parse list of Sub Objects.
     *
     * @param cb channel buffer
     * @return list of Sub Objects
     * @throws PcepParseException when fails to parse sub object list
     */
    protected static LinkedList parseSubObjects(ChannelBuffer cb) throws PcepParseException {

        LinkedList subObjectList = new LinkedList<>();

        while (0 < cb.readableBytes()) {

            //check the Type of the TLV
            short type = cb.readByte();
            type = (short) (type & (TYPE_SHIFT_VALUE));
            byte hLength = cb.readByte();

            PcepValueType subObj;

            switch (type) {

            case IPv4SubObject.TYPE:
                subObj = IPv4SubObject.read(cb);
                break;
            case IPv6SubObject.TYPE:
                byte[] ipv6Value = new byte[IPv6SubObject.VALUE_LENGTH];
                cb.readBytes(ipv6Value, 0, IPv6SubObject.VALUE_LENGTH);
                subObj = new IPv6SubObject(ipv6Value);
                break;
            case AutonomousSystemNumberSubObject.TYPE:
                subObj = AutonomousSystemNumberSubObject.read(cb);
                break;
            case PathKeySubObject.TYPE:
                subObj = PathKeySubObject.read(cb);
                break;
            case SrEroSubObject.TYPE:
                subObj = SrEroSubObject.read(cb);
                break;
            default:
                throw new PcepParseException("Unexpected sub object. Type: " + (int) type);
            }
            // Check for the padding
            int pad = hLength % 4;
            if (0 < pad) {
                pad = 4 - pad;
                if (pad <= cb.readableBytes()) {
                    cb.skipBytes(pad);
                }
            }

            subObjectList.add(subObj);
        }
        if (0 < cb.readableBytes()) {
            throw new PcepParseException("Subobject parsing error. Extra bytes received.");
        }
        return subObjectList;
    }

    @Override
    public int write(ChannelBuffer cb) throws PcepParseException {

        //write Object header
        int objStartIndex = cb.writerIndex();

        int objLenIndex = eroObjHeader.write(cb);

        if (objLenIndex <= 0) {
            throw new PcepParseException("Failed to write ERO object header. Index " + objLenIndex);
        }

        ListIterator listIterator = subObjectList.listIterator();

        while (listIterator.hasNext()) {
            listIterator.next().write(cb);
        }

        //Update object length now
        int length = cb.writerIndex() - objStartIndex;
        cb.setShort(objLenIndex, (short) length);
        //will be helpful during print().
        eroObjHeader.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;
        }

        objLenIndex = cb.writerIndex();
        return objLenIndex;
    }

    /**
     * Builder class for PCEP ERO object.
     */
    public static class Builder implements PcepEroObject.Builder {

        private boolean bIsHeaderSet = false;

        private boolean bIsPFlagSet = false;
        private boolean bPFlag;

        private boolean bIsIFlagSet = false;
        private boolean bIFlag;

        private PcepObjectHeader eroObjHeader;
        LinkedList subObjectList = new LinkedList<>();

        @Override
        public PcepEroObject build() {

            PcepObjectHeader eroObjHeader = this.bIsHeaderSet ? this.eroObjHeader : DEFAULT_ERO_OBJECT_HEADER;

            if (bIsPFlagSet) {
                eroObjHeader.setPFlag(bPFlag);
            }

            if (bIsIFlagSet) {
                eroObjHeader.setIFlag(bIFlag);
            }

            return new PcepEroObjectVer1(eroObjHeader, this.subObjectList);
        }

        @Override
        public PcepObjectHeader getEroObjHeader() {
            return this.eroObjHeader;
        }

        @Override
        public Builder setEroObjHeader(PcepObjectHeader obj) {
            this.eroObjHeader = obj;
            this.bIsHeaderSet = true;
            return this;
        }

        @Override
        public LinkedList getSubObjects() {
            return this.subObjectList;
        }

        @Override
        public Builder setSubObjects(LinkedList subObjectList) {
            this.subObjectList = subObjectList;
            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 int hashCode() {
        return Objects.hash(eroObjHeader, subObjectList);
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(getClass()).omitNullValues()
                .add("EroObjHeader", eroObjHeader)
                .add("SubObjects", subObjectList)
                .toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (obj instanceof PcepEroObjectVer1) {
            int countObjSubTlv = 0;
            int countOtherSubTlv = 0;
            boolean isCommonSubTlv = true;
            PcepEroObjectVer1 other = (PcepEroObjectVer1) obj;
            Iterator objListIterator = other.subObjectList.iterator();
            countOtherSubTlv = other.subObjectList.size();
            countObjSubTlv = subObjectList.size();
            if (countObjSubTlv != countOtherSubTlv) {
                return false;
            } else {
                while (objListIterator.hasNext() && isCommonSubTlv) {
                    PcepValueType subTlv = objListIterator.next();
                    if (subObjectList.contains(subTlv)) {
                        isCommonSubTlv = Objects.equals(subObjectList.get(subObjectList.indexOf(subTlv)),
                                         other.subObjectList.get(other.subObjectList.indexOf(subTlv)));
                    } else {
                        isCommonSubTlv = false;
                    }
                }
                return isCommonSubTlv && Objects.equals(eroObjHeader, other.eroObjHeader);
            }
        }
        return false;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy