blob: d680ff44a5d8560db2a3bfca8d5b8d57cbae9182 [file] [log] [blame]
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -07003 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17package org.onosproject.pcepio.protocol.ver1;
18
Priyanka B413fbe82016-05-26 11:44:45 +053019import java.util.Iterator;
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -070020import java.util.LinkedList;
21import java.util.ListIterator;
Priyanka B413fbe82016-05-26 11:44:45 +053022import java.util.Objects;
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -070023
24import org.jboss.netty.buffer.ChannelBuffer;
25import org.onosproject.pcepio.exceptions.PcepParseException;
26import org.onosproject.pcepio.protocol.PcepEroObject;
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +053027import org.onosproject.pcepio.types.AutonomousSystemNumberSubObject;
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -070028import org.onosproject.pcepio.types.IPv4SubObject;
29import org.onosproject.pcepio.types.IPv6SubObject;
30import org.onosproject.pcepio.types.PathKeySubObject;
31import org.onosproject.pcepio.types.PcepErrorDetailInfo;
32import org.onosproject.pcepio.types.PcepObjectHeader;
33import org.onosproject.pcepio.types.PcepValueType;
34import org.onosproject.pcepio.types.SrEroSubObject;
35import org.slf4j.Logger;
36import org.slf4j.LoggerFactory;
37
38import com.google.common.base.MoreObjects;
39
40/**
41 * Provides PCEP Ero Object.
42 */
43public class PcepEroObjectVer1 implements PcepEroObject {
44 /*
45 * rfc3209
46 0 1 2 3
47 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
48 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49 | Object-Class | OT |Res|P|I| Object Length (bytes) |
50 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 | |
52 // (Subobjects) //
53 | |
54 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55
56 If a Path message contains multiple EXPLICIT_ROUTE objects, only the
57 first object is meaningful. Subsequent EXPLICIT_ROUTE objects MAY be
58 ignored and SHOULD NOT be propagated.
59
60 In current implementation, only strict hops are supported. So,
61 empty ERO with no sub-objects is considered illegal.
62
63 Subobjects:
64 0 1
65 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
66 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+
67 |L| Type | Length | (Subobject contents) |
68 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+
69
70 L
71
72 The L bit is an attribute of the subobject. The L bit is set
73 if the subobject represents a loose hop in the explicit route.
74 If the bit is not set, the subobject represents a strict hop in
75 the explicit route.
76
77 Type
78
79 The Type indicates the type of contents of the subobject.
80
81
82 Subobject 1: IPv4 address
83
84 0 1 2 3
85 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
86 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
87 |L| Type | Length | IPv4 address (4 bytes) |
88 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
89 | IPv4 address (continued) | Prefix Length | Resvd |
90 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
91
92 Subobject 2: IPv6 Prefix
93
94 0 1 2 3
95 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
96 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97 |L| Type | Length | IPv6 address (16 bytes) |
98 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99 | IPv6 address (continued) |
100 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
101 | IPv6 address (continued) |
102 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
103 | IPv6 address (continued) |
104 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
105 | IPv6 address (continued) | Prefix Length | Resvd |
106 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
107
108 Subobject 3: Autonomous System Number
109
110 The contents of an Autonomous System (AS) number subobject are a 2-
111 octet AS number. The abstract node represented by this subobject is
112 the set of nodes belonging to the autonomous system.
113
114 The length of the AS number subobject is 4 octets.
115
116 Subobject 4: PATH_KEY_32_BIT_SUB_OBJ_TYPE:
117
118 Pathkey subobject(RFC 5520):
119 0 1 2 3
120 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
121 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
122 |L| Type | Length | Path-Key |
123 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
124 | PCE ID (4 bytes) |
125 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
126
127 Subobject 5: SR_ERO_SUB_OBJ_TYPE:
128
129 SR-ERO subobject: (draft-ietf-pce-segment-routing-00)
130 0 1 2 3
131 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
132 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
133 |L| Type | Length | ST | Flags |F|S|C|M|
134 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
135 | SID |
136 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
137 // NAI (variable) //
138 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
139 */
140
141 protected static final Logger log = LoggerFactory.getLogger(PcepEroObjectVer1.class);
142
143 public static final byte ERO_OBJ_TYPE = 1;
144 public static final byte ERO_OBJ_CLASS = 7;
145 public static final byte ERO_OBJECT_VERSION = 1;
146 public static final short ERO_OBJ_MINIMUM_LENGTH = 12;
147 public static final byte IPV4_TYPE = 1;
148 public static final byte PATH_KEY_32_BIT_SUB_OBJ_TYPE = 64;
149 public static final int LABEL_SUB_OBJ_TYPE = 3;
150 public static final int SR_ERO_SUB_OBJ_TYPE = 96;
151 public static final int OBJECT_HEADER_LENGTH = 4;
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530152 public static final int TYPE_SHIFT_VALUE = 0x7F;
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700153
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530154 public static final PcepObjectHeader DEFAULT_ERO_OBJECT_HEADER = new PcepObjectHeader(ERO_OBJ_CLASS, ERO_OBJ_TYPE,
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700155 PcepObjectHeader.REQ_OBJ_OPTIONAL_PROCESS, PcepObjectHeader.RSP_OBJ_PROCESSED, ERO_OBJ_MINIMUM_LENGTH);
156
157 private PcepObjectHeader eroObjHeader;
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530158 private LinkedList<PcepValueType> subObjectList = new LinkedList<>();
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700159
160 /**
161 * reset variables.
162 */
163 public PcepEroObjectVer1() {
164 this.eroObjHeader = null;
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530165 this.subObjectList = null;
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700166 }
167
168 /**
169 * Constructor to initialize parameters of ERO object.
170 *
171 * @param eroObjHeader ERO object header
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530172 * @param subObjectList list of sub objects.
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700173 */
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530174 public PcepEroObjectVer1(PcepObjectHeader eroObjHeader, LinkedList<PcepValueType> subObjectList) {
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700175
176 this.eroObjHeader = eroObjHeader;
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530177 this.subObjectList = subObjectList;
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700178 }
179
180 /**
181 * Returns ERO object header.
182 *
183 * @return eroObjHeader ERO object header
184 */
185 public PcepObjectHeader getEroObjHeader() {
186 return this.eroObjHeader;
187 }
188
189 /**
190 * Sets Object Header.
191 *
192 * @param obj ERO object header
193 */
194 public void setEroObjHeader(PcepObjectHeader obj) {
195 this.eroObjHeader = obj;
196 }
197
198 @Override
199 public LinkedList<PcepValueType> getSubObjects() {
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530200 return this.subObjectList;
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700201 }
202
203 @Override
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530204 public void setSubObjects(LinkedList<PcepValueType> subObjectList) {
205 this.subObjectList = subObjectList;
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700206 }
207
208 /**
209 * Reads from channel buffer and returns object of PcepEroObject.
210 *
211 * @param cb channel buffer.
212 * @return object of PcepEroObject
213 * @throws PcepParseException when ERO object is not present in channel buffer
214 */
215 public static PcepEroObject read(ChannelBuffer cb) throws PcepParseException {
216
217 PcepObjectHeader eroObjHeader;
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530218 LinkedList<PcepValueType> subObjectList = new LinkedList<>();
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700219
220 eroObjHeader = PcepObjectHeader.read(cb);
221
222 if (eroObjHeader.getObjClass() != PcepEroObjectVer1.ERO_OBJ_CLASS) {
223 log.debug("ErrorType:" + PcepErrorDetailInfo.ERROR_TYPE_6 + " ErrorValue:"
224 + PcepErrorDetailInfo.ERROR_VALUE_9);
225 throw new PcepParseException(PcepErrorDetailInfo.ERROR_TYPE_6, PcepErrorDetailInfo.ERROR_VALUE_9);
226 }
227
228 if (eroObjHeader.getObjLen() > OBJECT_HEADER_LENGTH) {
229 ChannelBuffer tempCb = cb.readBytes(eroObjHeader.getObjLen() - OBJECT_HEADER_LENGTH);
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530230 subObjectList = parseSubObjects(tempCb);
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700231 }
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530232 return new PcepEroObjectVer1(eroObjHeader, subObjectList);
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700233 }
234
235 /**
236 * Parse list of Sub Objects.
237 *
238 * @param cb channel buffer
239 * @return list of Sub Objects
240 * @throws PcepParseException when fails to parse sub object list
241 */
242 protected static LinkedList<PcepValueType> parseSubObjects(ChannelBuffer cb) throws PcepParseException {
243
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530244 LinkedList<PcepValueType> subObjectList = new LinkedList<>();
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700245
246 while (0 < cb.readableBytes()) {
247
248 //check the Type of the TLV
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530249 short type = cb.readByte();
250 type = (short) (type & (TYPE_SHIFT_VALUE));
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700251 byte hLength = cb.readByte();
252
253 PcepValueType subObj;
254
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530255 switch (type) {
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700256
257 case IPv4SubObject.TYPE:
258 subObj = IPv4SubObject.read(cb);
259 break;
260 case IPv6SubObject.TYPE:
261 byte[] ipv6Value = new byte[IPv6SubObject.VALUE_LENGTH];
262 cb.readBytes(ipv6Value, 0, IPv6SubObject.VALUE_LENGTH);
263 subObj = new IPv6SubObject(ipv6Value);
264 break;
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530265 case AutonomousSystemNumberSubObject.TYPE:
266 subObj = AutonomousSystemNumberSubObject.read(cb);
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700267 break;
268 case PathKeySubObject.TYPE:
269 subObj = PathKeySubObject.read(cb);
270 break;
271 case SrEroSubObject.TYPE:
272 subObj = SrEroSubObject.read(cb);
273 break;
274 default:
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530275 throw new PcepParseException("Unexpected sub object. Type: " + (int) type);
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700276 }
277 // Check for the padding
278 int pad = hLength % 4;
279 if (0 < pad) {
280 pad = 4 - pad;
281 if (pad <= cb.readableBytes()) {
282 cb.skipBytes(pad);
283 }
284 }
285
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530286 subObjectList.add(subObj);
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700287 }
288 if (0 < cb.readableBytes()) {
289 throw new PcepParseException("Subobject parsing error. Extra bytes received.");
290 }
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530291 return subObjectList;
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700292 }
293
294 @Override
295 public int write(ChannelBuffer cb) throws PcepParseException {
296
297 //write Object header
298 int objStartIndex = cb.writerIndex();
299
300 int objLenIndex = eroObjHeader.write(cb);
301
302 if (objLenIndex <= 0) {
303 throw new PcepParseException("Failed to write ERO object header. Index " + objLenIndex);
304 }
305
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530306 ListIterator<PcepValueType> listIterator = subObjectList.listIterator();
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700307
308 while (listIterator.hasNext()) {
309 listIterator.next().write(cb);
310 }
311
312 //Update object length now
313 int length = cb.writerIndex() - objStartIndex;
314 cb.setShort(objLenIndex, (short) length);
315 //will be helpful during print().
316 eroObjHeader.setObjLen((short) length);
317
318 //As per RFC the length of object should be multiples of 4
319 int pad = length % 4;
320
321 if (pad != 0) {
322 pad = 4 - pad;
323 for (int i = 0; i < pad; i++) {
324 cb.writeByte((byte) 0);
325 }
326 length = length + pad;
327 }
328
329 objLenIndex = cb.writerIndex();
330 return objLenIndex;
331 }
332
333 /**
334 * Builder class for PCEP ERO object.
335 */
336 public static class Builder implements PcepEroObject.Builder {
337
338 private boolean bIsHeaderSet = false;
339
340 private boolean bIsPFlagSet = false;
341 private boolean bPFlag;
342
343 private boolean bIsIFlagSet = false;
344 private boolean bIFlag;
345
346 private PcepObjectHeader eroObjHeader;
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530347 LinkedList<PcepValueType> subObjectList = new LinkedList<>();
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700348
349 @Override
350 public PcepEroObject build() {
351
352 PcepObjectHeader eroObjHeader = this.bIsHeaderSet ? this.eroObjHeader : DEFAULT_ERO_OBJECT_HEADER;
353
354 if (bIsPFlagSet) {
355 eroObjHeader.setPFlag(bPFlag);
356 }
357
358 if (bIsIFlagSet) {
359 eroObjHeader.setIFlag(bIFlag);
360 }
361
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530362 return new PcepEroObjectVer1(eroObjHeader, this.subObjectList);
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700363 }
364
365 @Override
366 public PcepObjectHeader getEroObjHeader() {
367 return this.eroObjHeader;
368 }
369
370 @Override
371 public Builder setEroObjHeader(PcepObjectHeader obj) {
372 this.eroObjHeader = obj;
373 this.bIsHeaderSet = true;
374 return this;
375 }
376
377 @Override
378 public LinkedList<PcepValueType> getSubObjects() {
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530379 return this.subObjectList;
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700380 }
381
382 @Override
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530383 public Builder setSubObjects(LinkedList<PcepValueType> subObjectList) {
384 this.subObjectList = subObjectList;
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700385 return this;
386 }
387
388 @Override
389 public Builder setPFlag(boolean value) {
390 this.bPFlag = value;
391 this.bIsPFlagSet = true;
392 return this;
393 }
394
395 @Override
396 public Builder setIFlag(boolean value) {
397 this.bIFlag = value;
398 this.bIsIFlagSet = true;
399 return this;
400 }
401 }
402
403 @Override
Priyanka B413fbe82016-05-26 11:44:45 +0530404 public int hashCode() {
405 return Objects.hash(eroObjHeader, subObjectList);
406 }
407
408 @Override
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700409 public String toString() {
Mahesh Poojary Sf1bbd362016-02-25 18:19:59 +0530410 return MoreObjects.toStringHelper(getClass()).omitNullValues()
411 .add("EroObjHeader", eroObjHeader)
412 .add("SubObjects", subObjectList)
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700413 .toString();
414 }
Priyanka B413fbe82016-05-26 11:44:45 +0530415
416 @Override
417 public boolean equals(Object obj) {
418 if (this == obj) {
419 return true;
420 }
421
422 if (obj instanceof PcepEroObjectVer1) {
423 int countObjSubTlv = 0;
424 int countOtherSubTlv = 0;
425 boolean isCommonSubTlv = true;
426 PcepEroObjectVer1 other = (PcepEroObjectVer1) obj;
427 Iterator<PcepValueType> objListIterator = other.subObjectList.iterator();
428 countOtherSubTlv = other.subObjectList.size();
429 countObjSubTlv = subObjectList.size();
430 if (countObjSubTlv != countOtherSubTlv) {
431 return false;
432 } else {
433 while (objListIterator.hasNext() && isCommonSubTlv) {
434 PcepValueType subTlv = objListIterator.next();
435 if (subObjectList.contains(subTlv)) {
436 isCommonSubTlv = Objects.equals(subObjectList.get(subObjectList.indexOf(subTlv)),
437 other.subObjectList.get(other.subObjectList.indexOf(subTlv)));
438 } else {
439 isCommonSubTlv = false;
440 }
441 }
442 return isCommonSubTlv && Objects.equals(eroObjHeader, other.eroObjHeader);
443 }
444 }
445 return false;
446 }
Sho SHIMIZUe81e4db2015-09-03 09:44:38 -0700447}