2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.protocol.pcep.impl;
10 import java.util.ArrayList;
11 import java.util.List;
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
16 import org.opendaylight.protocol.util.ByteArray;
17 import org.opendaylight.protocol.concepts.IPv4Address;
18 import org.opendaylight.protocol.concepts.IPv6Address;
19 import org.opendaylight.protocol.pcep.PCEPDeserializerException;
20 import org.opendaylight.protocol.pcep.PCEPTlv;
21 import org.opendaylight.protocol.pcep.concepts.LSPSymbolicName;
22 import org.opendaylight.protocol.pcep.impl.tlv.LSPIdentifierIPv4TlvParser;
23 import org.opendaylight.protocol.pcep.impl.tlv.LSPIdentifierIPv6TlvParser;
24 import org.opendaylight.protocol.pcep.impl.tlv.NoPathVectorTlvParser;
25 import org.opendaylight.protocol.pcep.impl.tlv.OFListTlvParser;
26 import org.opendaylight.protocol.pcep.impl.tlv.PCEStatefulCapabilityTlvParser;
27 import org.opendaylight.protocol.pcep.impl.tlv.RSVPErrorSpecIPv4TlvParser;
28 import org.opendaylight.protocol.pcep.impl.tlv.RSVPErrorSpecIPv6TlvParser;
29 import org.opendaylight.protocol.pcep.tlv.IPv4LSPIdentifiersTlv;
30 import org.opendaylight.protocol.pcep.tlv.IPv6LSPIdentifiersTlv;
31 import org.opendaylight.protocol.pcep.tlv.LSPCleanupTlv;
32 import org.opendaylight.protocol.pcep.tlv.LSPStateDBVersionTlv;
33 import org.opendaylight.protocol.pcep.tlv.LSPSymbolicNameTlv;
34 import org.opendaylight.protocol.pcep.tlv.LSPUpdateErrorTlv;
35 import org.opendaylight.protocol.pcep.tlv.NoPathVectorTlv;
36 import org.opendaylight.protocol.pcep.tlv.NodeIdentifierTlv;
37 import org.opendaylight.protocol.pcep.tlv.OFListTlv;
38 import org.opendaylight.protocol.pcep.tlv.OrderTlv;
39 import org.opendaylight.protocol.pcep.tlv.OverloadedDurationTlv;
40 import org.opendaylight.protocol.pcep.tlv.P2MPCapabilityTlv;
41 import org.opendaylight.protocol.pcep.tlv.PCEStatefulCapabilityTlv;
42 import org.opendaylight.protocol.pcep.tlv.RSVPErrorSpecTlv;
43 import org.opendaylight.protocol.pcep.tlv.ReqMissingTlv;
46 * Parser for {@link org.opendaylight.protocol.pcep.PCEPTlv PCEPTlv} and its subclasses
48 public final class PCEPTlvParser {
50 private static final Logger logger = LoggerFactory.getLogger(PCEPTlvParser.class);
53 * Type indicator for {@link org.opendaylight.protocol.pcep.PCEPTlv PCEPTlv}
55 private enum PCEPTlvType {
57 OVERLOADED_DURATION(2),
62 PCE_STATEFUL_CAPABILITY(16),
63 LSP_SYMBOLIC_NAME(17),
64 LSP_IDENTIFIER_IPV4(18),
65 LSP_IDENTIFIER_IPV6(19),
67 RSVP_ERROR_SPEC_IPV4(21),
68 RSVP_ERROR_SPEC_IPV6(22),
69 LSP_STATE_DB_VERSION(23),
70 // TODO: use IANA defined number - for now has been used first unused
75 private final int indicator;
77 PCEPTlvType(final int indicator) {
78 this.indicator = indicator;
81 public int getIndicator() {
82 return this.indicator;
85 public static PCEPTlvType getFromInt(final int type) throws PCEPDeserializerException {
87 for (final PCEPTlvType type_e : PCEPTlvType.values()) {
88 if (type_e.getIndicator() == type)
92 throw new PCEPDeserializerException("Unknown TLV type: " + type);
97 * Fields lengths in Bytes
99 public static final int TYPE_F_LENGTH = 2;
100 public static final int LENGTH_F_LENGTH = 2;
101 public static final int HEADER_LENGTH = LENGTH_F_LENGTH + TYPE_F_LENGTH;
104 * Fields offsets in Bytes
106 public static final int TYPE_F_OFFSET = 0;
107 public static final int LENGTH_F_OFFSET = TYPE_F_OFFSET + TYPE_F_LENGTH;
108 public static final int VALUE_F_OFFSET = LENGTH_F_OFFSET + LENGTH_F_LENGTH;
111 * padding of value field in bytes
113 public static final int PADDED_TO = 4;
116 * constants for specific one-value tlvs
118 private static final int DBV_F_LENGTH = 8;
119 private static final int OVERLOADED_DURATION_LENGTH = 4;
120 private static final int UPDATE_ERR_CODE_LENGTH = 4;
121 private static final int REQ_ID_LENGTH = 4;
122 private static final int ORDR_DEL_LENGTH = 4;
123 private static final int ORDR_SETUP_LENGTH = 4;
124 private static final int P2MP_CAPABLITY_LENGTH = 2;
126 public static List<PCEPTlv> parse(final byte[] bytes) throws PCEPDeserializerException {
128 throw new IllegalArgumentException("Byte array is mandatory.");
130 final List<PCEPTlv> tlvList = new ArrayList<PCEPTlv>();
135 while (offset + HEADER_LENGTH < bytes.length) {
137 length = ByteArray.bytesToInt(ByteArray.subByte(bytes, offset + LENGTH_F_OFFSET, LENGTH_F_LENGTH));
139 type = PCEPTlvType.getFromInt(ByteArray.bytesToInt(ByteArray.subByte(bytes, offset + TYPE_F_OFFSET, TYPE_F_LENGTH)));
141 if (HEADER_LENGTH + length > bytes.length - offset)
142 throw new PCEPDeserializerException("Wrong length specified. Passed: " + (HEADER_LENGTH + length) + "; Expected: <= " + (bytes.length - offset)
145 final byte[] tlvBytes = ByteArray.subByte(bytes, offset + VALUE_F_OFFSET, length);
147 logger.trace("Attempt to parse tlv from bytes: {}", ByteArray.bytesToHexString(tlvBytes));
148 final PCEPTlv tlv = parseSpecificTLV(type, tlvBytes);
149 logger.trace("Tlv was parsed. {}", tlv);
153 offset += HEADER_LENGTH + length + Util.getPadding(HEADER_LENGTH + length, PADDED_TO);
159 public static byte[] put(final List<PCEPTlv> objsToSerialize) {
160 final List<byte[]> bytesList = new ArrayList<byte[]>(objsToSerialize.size());
163 for (final PCEPTlv obj : objsToSerialize) {
164 final byte[] bytes = put(obj);
165 length += bytes.length;
166 bytesList.add(bytes);
169 final byte[] retBytes = new byte[length];
172 for (final byte[] bytes : bytesList) {
173 System.arraycopy(bytes, 0, retBytes, offset, bytes.length);
174 offset += bytes.length;
180 public static byte[] put(final PCEPTlv objToSerialize) {
181 int typeIndicator = 0;
185 if (objToSerialize instanceof PCEStatefulCapabilityTlv) {
186 typeIndicator = PCEPTlvType.PCE_STATEFUL_CAPABILITY.getIndicator();
187 valueBytes = PCEStatefulCapabilityTlvParser.serializeValueField((PCEStatefulCapabilityTlv) objToSerialize);
188 } else if (objToSerialize instanceof LSPStateDBVersionTlv) {
189 typeIndicator = PCEPTlvType.LSP_STATE_DB_VERSION.getIndicator();
190 valueBytes = ByteArray.longToBytes(((LSPStateDBVersionTlv) objToSerialize).getDbVersion());
191 } else if (objToSerialize instanceof NoPathVectorTlv) {
192 typeIndicator = PCEPTlvType.NO_PATH_VECTOR.getIndicator();
193 valueBytes = NoPathVectorTlvParser.put((NoPathVectorTlv) objToSerialize);
194 } else if (objToSerialize instanceof OverloadedDurationTlv) {
195 typeIndicator = PCEPTlvType.OVERLOADED_DURATION.getIndicator();
196 valueBytes = ByteArray.intToBytes(((OverloadedDurationTlv) objToSerialize).getValue());
197 } else if (objToSerialize instanceof LSPSymbolicNameTlv) {
198 typeIndicator = PCEPTlvType.LSP_SYMBOLIC_NAME.getIndicator();
199 valueBytes = ((LSPSymbolicNameTlv) objToSerialize).getSymbolicName().getSymbolicName();
200 } else if (objToSerialize instanceof LSPUpdateErrorTlv) {
201 typeIndicator = PCEPTlvType.LSP_UPDATE_ERROR.getIndicator();
202 valueBytes = ((LSPUpdateErrorTlv) objToSerialize).getErrorCode();
204 assert valueBytes.length == UPDATE_ERR_CODE_LENGTH : "Update error code si too large.";
206 } else if (objToSerialize instanceof IPv4LSPIdentifiersTlv) {
207 typeIndicator = PCEPTlvType.LSP_IDENTIFIER_IPV4.getIndicator();
208 valueBytes = LSPIdentifierIPv4TlvParser.put((IPv4LSPIdentifiersTlv) objToSerialize);
209 } else if (objToSerialize instanceof IPv6LSPIdentifiersTlv) {
210 typeIndicator = PCEPTlvType.LSP_IDENTIFIER_IPV6.getIndicator();
211 valueBytes = LSPIdentifierIPv6TlvParser.put((IPv6LSPIdentifiersTlv) objToSerialize);
212 } else if (objToSerialize instanceof RSVPErrorSpecTlv<?> && ((RSVPErrorSpecTlv<?>) objToSerialize).getErrorNodeAddress() instanceof IPv4Address) {
213 typeIndicator = PCEPTlvType.RSVP_ERROR_SPEC_IPV4.getIndicator();
214 valueBytes = RSVPErrorSpecIPv4TlvParser.put((RSVPErrorSpecTlv<?>) objToSerialize);
215 } else if (objToSerialize instanceof RSVPErrorSpecTlv<?> && ((RSVPErrorSpecTlv<?>) objToSerialize).getErrorNodeAddress() instanceof IPv6Address) {
216 typeIndicator = PCEPTlvType.RSVP_ERROR_SPEC_IPV6.getIndicator();
217 valueBytes = RSVPErrorSpecIPv6TlvParser.put((RSVPErrorSpecTlv<?>) objToSerialize);
218 } else if (objToSerialize instanceof ReqMissingTlv) {
219 typeIndicator = PCEPTlvType.REQ_MISSING.getIndicator();
220 valueBytes = new byte[REQ_ID_LENGTH];
221 System.arraycopy(ByteArray.longToBytes(((ReqMissingTlv) objToSerialize).getRequestID()), Long.SIZE / Byte.SIZE - REQ_ID_LENGTH, valueBytes, 0,
223 } else if (objToSerialize instanceof NodeIdentifierTlv) {
224 typeIndicator = PCEPTlvType.NODE_IDENTIFIER.getIndicator();
225 valueBytes = ((NodeIdentifierTlv) objToSerialize).getValue();
226 } else if (objToSerialize instanceof OrderTlv) {
227 typeIndicator = PCEPTlvType.ORDER_TLV.getIndicator();
228 valueBytes = new byte[ORDR_DEL_LENGTH + ORDR_SETUP_LENGTH];
229 ByteArray.copyWhole(ByteArray.intToBytes((int) ((OrderTlv) objToSerialize).getDeleteOrder()), valueBytes, 0);
230 ByteArray.copyWhole(ByteArray.intToBytes((int) ((OrderTlv) objToSerialize).getSetupOrder()), valueBytes, ORDR_DEL_LENGTH);
231 } else if (objToSerialize instanceof P2MPCapabilityTlv) {
232 typeIndicator = PCEPTlvType.P2MP_CAPABILITY.getIndicator();
233 valueBytes = new byte[P2MP_CAPABLITY_LENGTH];
234 ByteArray.copyWhole(ByteArray.shortToBytes((short) ((P2MPCapabilityTlv) objToSerialize).getValue()), valueBytes, 0);
235 } else if (objToSerialize instanceof OFListTlv) {
236 typeIndicator = PCEPTlvType.OF_LIST_TLV.getIndicator();
237 valueBytes = OFListTlvParser.put((OFListTlv) objToSerialize);
238 } else if (objToSerialize instanceof LSPCleanupTlv) {
239 typeIndicator = PCEPTlvType.LSP_CLEANUP_TLV.getIndicator();
240 valueBytes = ByteArray.intToBytes(((LSPCleanupTlv) objToSerialize).getTimeout());
242 throw new IllegalArgumentException("Unknown instance of PCEPTlv. Passed: " + objToSerialize + ".");
244 final byte[] typeBytes = ByteArray.cutBytes(ByteArray.intToBytes(typeIndicator), (Integer.SIZE / 8) - TYPE_F_LENGTH);
245 final byte[] lengthBytes = ByteArray.cutBytes(ByteArray.intToBytes(valueBytes.length), (Integer.SIZE / 8) - LENGTH_F_LENGTH);
246 final byte[] bytes = new byte[HEADER_LENGTH + valueBytes.length + Util.getPadding(HEADER_LENGTH + valueBytes.length, PADDED_TO)];
248 System.arraycopy(typeBytes, 0, bytes, TYPE_F_OFFSET, TYPE_F_LENGTH);
249 System.arraycopy(lengthBytes, 0, bytes, LENGTH_F_OFFSET, LENGTH_F_LENGTH);
250 System.arraycopy(valueBytes, 0, bytes, VALUE_F_OFFSET, valueBytes.length);
255 private static PCEPTlv parseSpecificTLV(final PCEPTlvType type, final byte[] valueBytes) throws PCEPDeserializerException {
257 case PCE_STATEFUL_CAPABILITY:
258 return PCEStatefulCapabilityTlvParser.deserializeValueField(valueBytes);
259 case LSP_STATE_DB_VERSION:
260 return new LSPStateDBVersionTlv(ByteArray.bytesToLong(ByteArray.subByte(valueBytes, 0, DBV_F_LENGTH)));
262 return NoPathVectorTlvParser.parse(valueBytes);
263 case OVERLOADED_DURATION:
264 return new OverloadedDurationTlv(ByteArray.bytesToInt(ByteArray.subByte(valueBytes, 0, OVERLOADED_DURATION_LENGTH)));
265 case LSP_SYMBOLIC_NAME:
266 return new LSPSymbolicNameTlv(new LSPSymbolicName(valueBytes));
267 case LSP_UPDATE_ERROR:
268 return new LSPUpdateErrorTlv(valueBytes);
269 case LSP_IDENTIFIER_IPV4:
270 return LSPIdentifierIPv4TlvParser.parse(valueBytes);
271 case LSP_IDENTIFIER_IPV6:
272 return LSPIdentifierIPv6TlvParser.parse(valueBytes);
273 case RSVP_ERROR_SPEC_IPV4:
274 return RSVPErrorSpecIPv4TlvParser.parse(valueBytes);
275 case RSVP_ERROR_SPEC_IPV6:
276 return RSVPErrorSpecIPv6TlvParser.parse(valueBytes);
278 return new ReqMissingTlv(ByteArray.bytesToLong(ByteArray.subByte(valueBytes, 0, REQ_ID_LENGTH)));
279 case NODE_IDENTIFIER:
280 return new NodeIdentifierTlv(valueBytes);
282 return new OrderTlv(ByteArray.bytesToLong(ByteArray.subByte(valueBytes, 0, ORDR_DEL_LENGTH)), ByteArray.bytesToLong(ByteArray.subByte(
283 valueBytes, ORDR_DEL_LENGTH, ORDR_SETUP_LENGTH)));
284 case P2MP_CAPABILITY:
285 return new P2MPCapabilityTlv(ByteArray.bytesToShort(ByteArray.subByte(valueBytes, 0, P2MP_CAPABLITY_LENGTH)) & 0xFFFF);
287 return OFListTlvParser.parse(valueBytes);
288 case LSP_CLEANUP_TLV:
289 return new LSPCleanupTlv(ByteArray.bytesToInt(valueBytes));
291 throw new PCEPDeserializerException("Unknown TLV type. Passed: " + type + ";");