2 * Copyright 2015 Open Networking Laboratory
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.onosproject.pcepio.protocol.ver1;
19 import java.util.LinkedList;
20 import java.util.ListIterator;
22 import org.jboss.netty.buffer.ChannelBuffer;
23 import org.onosproject.pcepio.exceptions.PcepParseException;
24 import org.onosproject.pcepio.protocol.PcepEroObject;
25 import org.onosproject.pcepio.types.AutonomousSystemTlv;
26 import org.onosproject.pcepio.types.IPv4SubObject;
27 import org.onosproject.pcepio.types.IPv6SubObject;
28 import org.onosproject.pcepio.types.PathKeySubObject;
29 import org.onosproject.pcepio.types.PcepErrorDetailInfo;
30 import org.onosproject.pcepio.types.PcepObjectHeader;
31 import org.onosproject.pcepio.types.PcepValueType;
32 import org.onosproject.pcepio.types.SrEroSubObject;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
36 import com.google.common.base.MoreObjects;
39 * Provides PCEP Ero Object.
41 public class PcepEroObjectVer1 implements PcepEroObject {
45 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
46 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 | Object-Class | OT |Res|P|I| Object Length (bytes) |
48 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54 If a Path message contains multiple EXPLICIT_ROUTE objects, only the
55 first object is meaningful. Subsequent EXPLICIT_ROUTE objects MAY be
56 ignored and SHOULD NOT be propagated.
58 In current implementation, only strict hops are supported. So,
59 empty ERO with no sub-objects is considered illegal.
63 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
64 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+
65 |L| Type | Length | (Subobject contents) |
66 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+
70 The L bit is an attribute of the subobject. The L bit is set
71 if the subobject represents a loose hop in the explicit route.
72 If the bit is not set, the subobject represents a strict hop in
77 The Type indicates the type of contents of the subobject.
80 Subobject 1: IPv4 address
83 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
84 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
85 |L| Type | Length | IPv4 address (4 bytes) |
86 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
87 | IPv4 address (continued) | Prefix Length | Resvd |
88 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90 Subobject 2: IPv6 Prefix
93 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
94 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
95 |L| Type | Length | IPv6 address (16 bytes) |
96 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97 | IPv6 address (continued) |
98 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99 | IPv6 address (continued) |
100 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
101 | IPv6 address (continued) |
102 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
103 | IPv6 address (continued) | Prefix Length | Resvd |
104 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106 Subobject 3: Autonomous System Number
108 The contents of an Autonomous System (AS) number subobject are a 2-
109 octet AS number. The abstract node represented by this subobject is
110 the set of nodes belonging to the autonomous system.
112 The length of the AS number subobject is 4 octets.
114 Subobject 4: PATH_KEY_32_BIT_SUB_OBJ_TYPE:
116 Pathkey subobject(RFC 5520):
118 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
119 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
120 |L| Type | Length | Path-Key |
121 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
123 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
125 Subobject 5: SR_ERO_SUB_OBJ_TYPE:
127 SR-ERO subobject: (draft-ietf-pce-segment-routing-00)
129 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
130 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
131 |L| Type | Length | ST | Flags |F|S|C|M|
132 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
134 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
136 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
139 protected static final Logger log = LoggerFactory.getLogger(PcepEroObjectVer1.class);
141 public static final byte ERO_OBJ_TYPE = 1;
142 public static final byte ERO_OBJ_CLASS = 7;
143 public static final byte ERO_OBJECT_VERSION = 1;
144 public static final short ERO_OBJ_MINIMUM_LENGTH = 12;
145 public static final byte IPV4_TYPE = 1;
146 public static final byte PATH_KEY_32_BIT_SUB_OBJ_TYPE = 64;
147 public static final int LABEL_SUB_OBJ_TYPE = 3;
148 public static final int SR_ERO_SUB_OBJ_TYPE = 96;
149 public static final int OBJECT_HEADER_LENGTH = 4;
150 public static final int YTYPE_SHIFT_VALUE = 0x7F;
152 static final PcepObjectHeader DEFAULT_ERO_OBJECT_HEADER = new PcepObjectHeader(ERO_OBJ_CLASS, ERO_OBJ_TYPE,
153 PcepObjectHeader.REQ_OBJ_OPTIONAL_PROCESS, PcepObjectHeader.RSP_OBJ_PROCESSED, ERO_OBJ_MINIMUM_LENGTH);
155 private PcepObjectHeader eroObjHeader;
156 private LinkedList<PcepValueType> llSubObjects = new LinkedList<>();
161 public PcepEroObjectVer1() {
162 this.eroObjHeader = null;
163 this.llSubObjects = null;
167 * Constructor to initialize parameters of ERO object.
169 * @param eroObjHeader ERO object header
170 * @param llSubObjects list of sub objects.
172 public PcepEroObjectVer1(PcepObjectHeader eroObjHeader, LinkedList<PcepValueType> llSubObjects) {
174 this.eroObjHeader = eroObjHeader;
175 this.llSubObjects = llSubObjects;
179 * Returns ERO object header.
181 * @return eroObjHeader ERO object header
183 public PcepObjectHeader getEroObjHeader() {
184 return this.eroObjHeader;
188 * Sets Object Header.
190 * @param obj ERO object header
192 public void setEroObjHeader(PcepObjectHeader obj) {
193 this.eroObjHeader = obj;
197 public LinkedList<PcepValueType> getSubObjects() {
198 return this.llSubObjects;
202 public void setSubObjects(LinkedList<PcepValueType> llSubObjects) {
203 this.llSubObjects = llSubObjects;
207 * Reads from channel buffer and returns object of PcepEroObject.
209 * @param cb channel buffer.
210 * @return object of PcepEroObject
211 * @throws PcepParseException when ERO object is not present in channel buffer
213 public static PcepEroObject read(ChannelBuffer cb) throws PcepParseException {
215 PcepObjectHeader eroObjHeader;
216 LinkedList<PcepValueType> llSubObjects = new LinkedList<>();
218 eroObjHeader = PcepObjectHeader.read(cb);
220 if (eroObjHeader.getObjClass() != PcepEroObjectVer1.ERO_OBJ_CLASS) {
221 log.debug("ErrorType:" + PcepErrorDetailInfo.ERROR_TYPE_6 + " ErrorValue:"
222 + PcepErrorDetailInfo.ERROR_VALUE_9);
223 throw new PcepParseException(PcepErrorDetailInfo.ERROR_TYPE_6, PcepErrorDetailInfo.ERROR_VALUE_9);
226 if (eroObjHeader.getObjLen() > OBJECT_HEADER_LENGTH) {
227 ChannelBuffer tempCb = cb.readBytes(eroObjHeader.getObjLen() - OBJECT_HEADER_LENGTH);
228 llSubObjects = parseSubObjects(tempCb);
230 return new PcepEroObjectVer1(eroObjHeader, llSubObjects);
234 * Parse list of Sub Objects.
236 * @param cb channel buffer
237 * @return list of Sub Objects
238 * @throws PcepParseException when fails to parse sub object list
240 protected static LinkedList<PcepValueType> parseSubObjects(ChannelBuffer cb) throws PcepParseException {
242 LinkedList<PcepValueType> llSubObjects = new LinkedList<>();
244 while (0 < cb.readableBytes()) {
246 //check the Type of the TLV
247 byte yType = cb.readByte();
248 yType = (byte) (yType & (YTYPE_SHIFT_VALUE));
249 byte hLength = cb.readByte();
251 PcepValueType subObj;
255 case IPv4SubObject.TYPE:
256 subObj = IPv4SubObject.read(cb);
258 case IPv6SubObject.TYPE:
259 byte[] ipv6Value = new byte[IPv6SubObject.VALUE_LENGTH];
260 cb.readBytes(ipv6Value, 0, IPv6SubObject.VALUE_LENGTH);
261 subObj = new IPv6SubObject(ipv6Value);
263 case AutonomousSystemTlv.TYPE:
264 subObj = AutonomousSystemTlv.read(cb);
266 case PathKeySubObject.TYPE:
267 subObj = PathKeySubObject.read(cb);
269 case SrEroSubObject.TYPE:
270 subObj = SrEroSubObject.read(cb);
273 throw new PcepParseException("Unexpected sub object. Type: " + (int) yType);
275 // Check for the padding
276 int pad = hLength % 4;
279 if (pad <= cb.readableBytes()) {
284 llSubObjects.add(subObj);
286 if (0 < cb.readableBytes()) {
287 throw new PcepParseException("Subobject parsing error. Extra bytes received.");
293 public int write(ChannelBuffer cb) throws PcepParseException {
295 //write Object header
296 int objStartIndex = cb.writerIndex();
298 int objLenIndex = eroObjHeader.write(cb);
300 if (objLenIndex <= 0) {
301 throw new PcepParseException("Failed to write ERO object header. Index " + objLenIndex);
304 ListIterator<PcepValueType> listIterator = llSubObjects.listIterator();
306 while (listIterator.hasNext()) {
307 listIterator.next().write(cb);
310 //Update object length now
311 int length = cb.writerIndex() - objStartIndex;
312 cb.setShort(objLenIndex, (short) length);
313 //will be helpful during print().
314 eroObjHeader.setObjLen((short) length);
316 //As per RFC the length of object should be multiples of 4
317 int pad = length % 4;
321 for (int i = 0; i < pad; i++) {
322 cb.writeByte((byte) 0);
324 length = length + pad;
327 objLenIndex = cb.writerIndex();
332 * Builder class for PCEP ERO object.
334 public static class Builder implements PcepEroObject.Builder {
336 private boolean bIsHeaderSet = false;
338 private boolean bIsPFlagSet = false;
339 private boolean bPFlag;
341 private boolean bIsIFlagSet = false;
342 private boolean bIFlag;
344 private PcepObjectHeader eroObjHeader;
345 LinkedList<PcepValueType> llSubObjects = new LinkedList<>();
348 public PcepEroObject build() {
350 PcepObjectHeader eroObjHeader = this.bIsHeaderSet ? this.eroObjHeader : DEFAULT_ERO_OBJECT_HEADER;
353 eroObjHeader.setPFlag(bPFlag);
357 eroObjHeader.setIFlag(bIFlag);
360 return new PcepEroObjectVer1(eroObjHeader, this.llSubObjects);
364 public PcepObjectHeader getEroObjHeader() {
365 return this.eroObjHeader;
369 public Builder setEroObjHeader(PcepObjectHeader obj) {
370 this.eroObjHeader = obj;
371 this.bIsHeaderSet = true;
376 public LinkedList<PcepValueType> getSubObjects() {
377 return this.llSubObjects;
381 public Builder setSubObjects(LinkedList<PcepValueType> llSubObjects) {
382 this.llSubObjects = llSubObjects;
387 public Builder setPFlag(boolean value) {
389 this.bIsPFlagSet = true;
394 public Builder setIFlag(boolean value) {
396 this.bIsIFlagSet = true;
402 public String toString() {
403 return MoreObjects.toStringHelper(getClass())
404 .add("EroObjHeader", eroObjHeader).add("SubObjects", llSubObjects)