Revert "BUG-47 : unfinished PCEP migration to generated DTOs."
[bgpcep.git] / pcep / impl / src / main / java / org / opendaylight / protocol / pcep / impl / PCEPTlvParser.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.protocol.pcep.impl;
9
10 import java.util.ArrayList;
11 import java.util.List;
12
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
15
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;
44
45 /**
46  * Parser for {@link org.opendaylight.protocol.pcep.PCEPTlv PCEPTlv} and its subclasses
47  */
48 public final class PCEPTlvParser {
49
50     private static final Logger logger = LoggerFactory.getLogger(PCEPTlvParser.class);
51
52     /**
53      * Type indicator for {@link org.opendaylight.protocol.pcep.PCEPTlv PCEPTlv}
54      */
55     private enum PCEPTlvType {
56         NO_PATH_VECTOR(1),
57         OVERLOADED_DURATION(2),
58         REQ_MISSING(3),
59         OF_LIST_TLV(4),
60         ORDER_TLV(5),
61         P2MP_CAPABILITY(6),
62         PCE_STATEFUL_CAPABILITY(16),
63         LSP_SYMBOLIC_NAME(17),
64         LSP_IDENTIFIER_IPV4(18),
65         LSP_IDENTIFIER_IPV6(19),
66         LSP_UPDATE_ERROR(20),
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
71         // number
72         NODE_IDENTIFIER(24),
73         LSP_CLEANUP_TLV(26);
74
75         private final int indicator;
76
77         PCEPTlvType(final int indicator) {
78             this.indicator = indicator;
79         }
80
81         public int getIndicator() {
82             return this.indicator;
83         }
84
85         public static PCEPTlvType getFromInt(final int type) throws PCEPDeserializerException {
86
87             for (final PCEPTlvType type_e : PCEPTlvType.values()) {
88                 if (type_e.getIndicator() == type)
89                     return type_e;
90             }
91
92             throw new PCEPDeserializerException("Unknown TLV type: " + type);
93         }
94         }
95
96     /*
97      * Fields lengths in Bytes
98      */
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;
102
103     /*
104      * Fields offsets in Bytes
105      */
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;
109
110     /*
111      * padding of value field in bytes
112      */
113     public static final int PADDED_TO = 4;
114
115     /*
116      * constants for specific one-value tlvs
117      */
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;
125
126     public static List<PCEPTlv> parse(final byte[] bytes) throws PCEPDeserializerException {
127         if (bytes == null)
128             throw new IllegalArgumentException("Byte array is mandatory.");
129
130         final List<PCEPTlv> tlvList = new ArrayList<PCEPTlv>();
131         PCEPTlvType type;
132         int length;
133         int offset = 0;
134
135         while (offset + HEADER_LENGTH < bytes.length) {
136
137             length = ByteArray.bytesToInt(ByteArray.subByte(bytes, offset + LENGTH_F_OFFSET, LENGTH_F_LENGTH));
138
139             type = PCEPTlvType.getFromInt(ByteArray.bytesToInt(ByteArray.subByte(bytes, offset + TYPE_F_OFFSET, TYPE_F_LENGTH)));
140
141             if (HEADER_LENGTH + length > bytes.length - offset)
142                 throw new PCEPDeserializerException("Wrong length specified. Passed: " + (HEADER_LENGTH + length) + "; Expected: <= " + (bytes.length - offset)
143                         + ".");
144
145             final byte[] tlvBytes = ByteArray.subByte(bytes, offset + VALUE_F_OFFSET, length);
146
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);
150
151             tlvList.add(tlv);
152
153             offset += HEADER_LENGTH + length + Util.getPadding(HEADER_LENGTH + length, PADDED_TO);
154         }
155
156         return tlvList;
157     }
158
159     public static byte[] put(final List<PCEPTlv> objsToSerialize) {
160         final List<byte[]> bytesList = new ArrayList<byte[]>(objsToSerialize.size());
161
162         int length = 0;
163         for (final PCEPTlv obj : objsToSerialize) {
164             final byte[] bytes = put(obj);
165             length += bytes.length;
166             bytesList.add(bytes);
167         }
168
169         final byte[] retBytes = new byte[length];
170
171         int offset = 0;
172         for (final byte[] bytes : bytesList) {
173             System.arraycopy(bytes, 0, retBytes, offset, bytes.length);
174             offset += bytes.length;
175         }
176
177         return retBytes;
178     }
179
180     public static byte[] put(final PCEPTlv objToSerialize) {
181         int typeIndicator = 0;
182
183         byte[] valueBytes;
184
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();
203
204             assert valueBytes.length == UPDATE_ERR_CODE_LENGTH : "Update error code si too large.";
205
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,
222                     REQ_ID_LENGTH);
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());
241         } else
242             throw new IllegalArgumentException("Unknown instance of PCEPTlv. Passed: " + objToSerialize + ".");
243
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)];
247
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);
251
252         return bytes;
253     }
254
255     private static PCEPTlv parseSpecificTLV(final PCEPTlvType type, final byte[] valueBytes) throws PCEPDeserializerException {
256         switch (type) {
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)));
261             case NO_PATH_VECTOR:
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);
277             case REQ_MISSING:
278                 return new ReqMissingTlv(ByteArray.bytesToLong(ByteArray.subByte(valueBytes, 0, REQ_ID_LENGTH)));
279             case NODE_IDENTIFIER:
280                 return new NodeIdentifierTlv(valueBytes);
281             case ORDER_TLV:
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);
286             case OF_LIST_TLV:
287                 return OFListTlvParser.parse(valueBytes);
288             case LSP_CLEANUP_TLV:
289                 return new LSPCleanupTlv(ByteArray.bytesToInt(valueBytes));
290             default:
291                 throw new PCEPDeserializerException("Unknown TLV type. Passed: " + type + ";");
292         }
293     }
294 }