Merge "Randomize port to allow concurrent execution"
[bgpcep.git] / pcep / impl / src / main / java / org / opendaylight / protocol / pcep / impl / PCEPObjectFactory.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
9 package org.opendaylight.protocol.pcep.impl;
10
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.HashMap;
14 import java.util.List;
15
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19 import org.opendaylight.protocol.util.ByteArray;
20 import org.opendaylight.protocol.concepts.IPv4Address;
21 import org.opendaylight.protocol.concepts.IPv6Address;
22 import org.opendaylight.protocol.pcep.PCEPDeserializerException;
23 import org.opendaylight.protocol.pcep.PCEPDocumentedException;
24 import org.opendaylight.protocol.pcep.PCEPErrors;
25 import org.opendaylight.protocol.pcep.PCEPObject;
26 import org.opendaylight.protocol.pcep.impl.PCEPObjectIdentifier.ObjectClass;
27 import org.opendaylight.protocol.pcep.impl.object.PCEPBranchNodeListObjectParser;
28 import org.opendaylight.protocol.pcep.impl.object.PCEPCloseObjectParser;
29 import org.opendaylight.protocol.pcep.impl.object.PCEPEndPointsIPv4ObjectParser;
30 import org.opendaylight.protocol.pcep.impl.object.PCEPEndPointsIPv6ObjectParser;
31 import org.opendaylight.protocol.pcep.impl.object.PCEPErrorObjectParser;
32 import org.opendaylight.protocol.pcep.impl.object.PCEPExcludeRouteObjectParser;
33 import org.opendaylight.protocol.pcep.impl.object.PCEPExistingPathBandwidthObjectParser;
34 import org.opendaylight.protocol.pcep.impl.object.PCEPExplicitRouteObjectParser;
35 import org.opendaylight.protocol.pcep.impl.object.PCEPGlobalConstraintsObjectParser;
36 import org.opendaylight.protocol.pcep.impl.object.PCEPIncludeRouteObjectParser;
37 import org.opendaylight.protocol.pcep.impl.object.PCEPLoadBalancingObjectParser;
38 import org.opendaylight.protocol.pcep.impl.object.PCEPLspObjectParser;
39 import org.opendaylight.protocol.pcep.impl.object.PCEPLspaObjectParser;
40 import org.opendaylight.protocol.pcep.impl.object.PCEPMetricObjectParser;
41 import org.opendaylight.protocol.pcep.impl.object.PCEPNoPathObjectParser;
42 import org.opendaylight.protocol.pcep.impl.object.PCEPNonBranchNodeListObjectParser;
43 import org.opendaylight.protocol.pcep.impl.object.PCEPNotificationObjectParser;
44 import org.opendaylight.protocol.pcep.impl.object.PCEPObjectiveFunctionObjectParser;
45 import org.opendaylight.protocol.pcep.impl.object.PCEPOpenObjectParser;
46 import org.opendaylight.protocol.pcep.impl.object.PCEPP2MPEndPointsIPv4ObjectParser;
47 import org.opendaylight.protocol.pcep.impl.object.PCEPP2MPEndPointsIPv6ObjectParser;
48 import org.opendaylight.protocol.pcep.impl.object.PCEPReportedRouteObjectParser;
49 import org.opendaylight.protocol.pcep.impl.object.PCEPRequestParameterObjectParser;
50 import org.opendaylight.protocol.pcep.impl.object.PCEPRequestedPathBandwidthObjectParser;
51 import org.opendaylight.protocol.pcep.impl.object.PCEPSecondaryExplicitRouteObjectParser;
52 import org.opendaylight.protocol.pcep.impl.object.PCEPSecondaryRecordRouteObjectParser;
53 import org.opendaylight.protocol.pcep.impl.object.PCEPSvecObjectParser;
54 import org.opendaylight.protocol.pcep.impl.object.PCEPUnreachedIPv4DestinationObjectParser;
55 import org.opendaylight.protocol.pcep.impl.object.PCEPUnreachedIPv6DestinationObjectParser;
56 import org.opendaylight.protocol.pcep.impl.object.UnknownObject;
57 import org.opendaylight.protocol.pcep.object.PCEPBranchNodeListObject;
58 import org.opendaylight.protocol.pcep.object.PCEPBranchNodeObject;
59 import org.opendaylight.protocol.pcep.object.PCEPCloseObject;
60 import org.opendaylight.protocol.pcep.object.PCEPEndPointsObject;
61 import org.opendaylight.protocol.pcep.object.PCEPErrorObject;
62 import org.opendaylight.protocol.pcep.object.PCEPExcludeRouteObject;
63 import org.opendaylight.protocol.pcep.object.PCEPExistingPathBandwidthObject;
64 import org.opendaylight.protocol.pcep.object.PCEPExplicitRouteObject;
65 import org.opendaylight.protocol.pcep.object.PCEPGlobalConstraintsObject;
66 import org.opendaylight.protocol.pcep.object.PCEPIncludeRouteObject;
67 import org.opendaylight.protocol.pcep.object.PCEPLoadBalancingObject;
68 import org.opendaylight.protocol.pcep.object.PCEPLspObject;
69 import org.opendaylight.protocol.pcep.object.PCEPLspaObject;
70 import org.opendaylight.protocol.pcep.object.PCEPMetricObject;
71 import org.opendaylight.protocol.pcep.object.PCEPNoPathObject;
72 import org.opendaylight.protocol.pcep.object.PCEPNonBranchNodeListObject;
73 import org.opendaylight.protocol.pcep.object.PCEPNotificationObject;
74 import org.opendaylight.protocol.pcep.object.PCEPObjectiveFunctionObject;
75 import org.opendaylight.protocol.pcep.object.PCEPOpenObject;
76 import org.opendaylight.protocol.pcep.object.PCEPP2MPEndPointsObject;
77 import org.opendaylight.protocol.pcep.object.PCEPReportedRouteObject;
78 import org.opendaylight.protocol.pcep.object.PCEPRequestParameterObject;
79 import org.opendaylight.protocol.pcep.object.PCEPRequestedPathBandwidthObject;
80 import org.opendaylight.protocol.pcep.object.PCEPSecondaryExplicitRouteObject;
81 import org.opendaylight.protocol.pcep.object.PCEPSecondaryRecordRouteObject;
82 import org.opendaylight.protocol.pcep.object.PCEPSvecObject;
83 import org.opendaylight.protocol.pcep.object.PCEPUnreachedDestinationObject;
84
85 /**
86  * Factory for subclasses of {@link org.opendaylight.protocol.pcep.PCEPObject PCEPObject}
87  */
88 public class PCEPObjectFactory {
89
90     private static final Logger logger = LoggerFactory.getLogger(PCEPObjectFactory.class);
91
92     /**
93      * Map of parsers for subobjects of {@link org.opendaylight.protocol.pcep.PCEPObject
94      * PCEPObject}
95      */
96     private static class MapOfParsers extends HashMap<PCEPObjectIdentifier, PCEPObjectParser> {
97         private static final long serialVersionUID = 1L;
98
99         private final static MapOfParsers instance = new MapOfParsers();
100
101         private MapOfParsers() {
102             this.fillInMap();
103         }
104
105         private void fillInMap() {
106             this.put(new PCEPObjectIdentifier(ObjectClass.OPEN, 1), new PCEPOpenObjectParser());
107             this.put(new PCEPObjectIdentifier(ObjectClass.RP, 1), new PCEPRequestParameterObjectParser());
108             this.put(new PCEPObjectIdentifier(ObjectClass.NO_PATH, 1), new PCEPNoPathObjectParser());
109             this.put(new PCEPObjectIdentifier(ObjectClass.BANDWIDTH, 1), new PCEPRequestedPathBandwidthObjectParser());
110             this.put(new PCEPObjectIdentifier(ObjectClass.BANDWIDTH, 2), new PCEPExistingPathBandwidthObjectParser());
111             this.put(new PCEPObjectIdentifier(ObjectClass.METRIC, 1), new PCEPMetricObjectParser());
112             this.put(new PCEPObjectIdentifier(ObjectClass.END_POINTS, 1), new PCEPEndPointsIPv4ObjectParser());
113             this.put(new PCEPObjectIdentifier(ObjectClass.END_POINTS, 2), new PCEPEndPointsIPv6ObjectParser());
114             this.put(new PCEPObjectIdentifier(ObjectClass.LSPA, 1), new PCEPLspaObjectParser());
115             this.put(new PCEPObjectIdentifier(ObjectClass.SVEC, 1), new PCEPSvecObjectParser());
116             this.put(new PCEPObjectIdentifier(ObjectClass.NOTIFICATION, 1), new PCEPNotificationObjectParser());
117             this.put(new PCEPObjectIdentifier(ObjectClass.ERROR, 1), new PCEPErrorObjectParser());
118             this.put(new PCEPObjectIdentifier(ObjectClass.CLOSE, 1), new PCEPCloseObjectParser());
119             this.put(new PCEPObjectIdentifier(ObjectClass.LOAD_BALANCING, 1), new PCEPLoadBalancingObjectParser());
120             this.put(new PCEPObjectIdentifier(ObjectClass.LSP, 1), new PCEPLspObjectParser());
121             this.put(new PCEPObjectIdentifier(ObjectClass.ERO, 1), new PCEPExplicitRouteObjectParser());
122             this.put(new PCEPObjectIdentifier(ObjectClass.RRO, 1), new PCEPReportedRouteObjectParser());
123             this.put(new PCEPObjectIdentifier(ObjectClass.IRO, 1), new PCEPIncludeRouteObjectParser());
124
125             /* GCO extension */
126             this.put(new PCEPObjectIdentifier(ObjectClass.XRO, 1), new PCEPExcludeRouteObjectParser());
127             this.put(new PCEPObjectIdentifier(ObjectClass.OBJCETIVE_FUNCTION, 1), new PCEPObjectiveFunctionObjectParser());
128             this.put(new PCEPObjectIdentifier(ObjectClass.GLOBAL_CONSTRAINTS, 1), new PCEPGlobalConstraintsObjectParser());
129
130             /* RFC6006 */
131             this.put(new PCEPObjectIdentifier(ObjectClass.END_POINTS, 3), new PCEPP2MPEndPointsIPv4ObjectParser());
132             this.put(new PCEPObjectIdentifier(ObjectClass.END_POINTS, 4), new PCEPP2MPEndPointsIPv6ObjectParser());
133             this.put(new PCEPObjectIdentifier(ObjectClass.UNREACHED_DESTINATION, 1), new PCEPUnreachedIPv4DestinationObjectParser());
134             this.put(new PCEPObjectIdentifier(ObjectClass.UNREACHED_DESTINATION, 2), new PCEPUnreachedIPv6DestinationObjectParser());
135             this.put(new PCEPObjectIdentifier(ObjectClass.SERO, 1), new PCEPSecondaryExplicitRouteObjectParser());
136             this.put(new PCEPObjectIdentifier(ObjectClass.SRRO, 1), new PCEPSecondaryRecordRouteObjectParser());
137             this.put(new PCEPObjectIdentifier(ObjectClass.BRANCH_NODE, 1), new PCEPBranchNodeListObjectParser());
138             this.put(new PCEPObjectIdentifier(ObjectClass.BRANCH_NODE, 2), new PCEPNonBranchNodeListObjectParser());
139         }
140
141         public static MapOfParsers getInstance() {
142             return instance;
143         }
144     }
145
146     private static PCEPObject parse(final byte[] bytes, final PCEPObjectHeader header) throws PCEPDocumentedException, PCEPDeserializerException {
147                 if (bytes == null)
148                     throw new IllegalArgumentException("Array of bytes is mandatory.");
149                 if (header == null)
150                     throw new IllegalArgumentException("PCEPObjectHeader is mandatory.");
151
152                 logger.trace("Attempt to parse object from bytes: {}", ByteArray.bytesToHexString(bytes));
153
154                 /*
155                  * if PCEPObjectIdentifier.getObjectClassFromInt() don't throws
156                  * exception and if Map.get() returns null, we know that we can't
157                  * recognize OBJ TYPE.
158                  */
159                 final PCEPObjectParser objParserClass = MapOfParsers.getInstance().get(
160                         new PCEPObjectIdentifier(PCEPObjectIdentifier.ObjectClass.getFromInt(header.objClass), header.objType));
161                 if (objParserClass == null) {
162                         logger.debug("Object could not be parsed. Header: {}. Body bytes: {}", header, Arrays.toString(bytes));
163                     throw new PCEPDocumentedException("Unrecognized object type: " + header.objType + " for object class: " + header.objClass,
164                             PCEPErrors.UNRECOGNIZED_OBJ_TYPE);
165                 }
166                 final PCEPObject obj = objParserClass.parse(bytes, header.processed, header.ignored);
167                 logger.trace("Object was parsed. {}", obj);
168                 return obj;
169     }
170
171     public static List<PCEPObject> parseObjects(final byte[] bytes) throws PCEPDeserializerException, PCEPDocumentedException {
172                 int offset = 0;
173                 final List<PCEPObject> objs = new ArrayList<PCEPObject>();
174
175                 while (bytes.length - offset > 0) {
176                     if (bytes.length - offset < PCEPObjectHeader.COMMON_OBJECT_HEADER_LENGTH)
177                         throw new PCEPDeserializerException("Too few bytes in passed array. Passed: " + (bytes.length - offset) + " Expected: >= "
178                                 + PCEPObjectHeader.COMMON_OBJECT_HEADER_LENGTH + ".");
179
180                     final PCEPObjectHeader header = PCEPObjectHeader.parseHeader(Arrays.copyOfRange(bytes, offset, offset
181                             + PCEPObjectHeader.COMMON_OBJECT_HEADER_LENGTH));
182
183                     if (bytes.length - offset < header.objLength)
184                         throw new PCEPDeserializerException("Too few bytes in passed array. Passed: " + (bytes.length - offset) + " Expected: >= " + header.objLength
185                                 + ".");
186
187                     // copy bytes for deeper parsing
188                     final byte[] bytesToPass = ByteArray.subByte(bytes, offset + PCEPObjectHeader.COMMON_OBJECT_HEADER_LENGTH, header.objLength
189                             - PCEPObjectHeader.COMMON_OBJECT_HEADER_LENGTH);
190
191                     offset += header.objLength;
192
193                     // if obj is not-supported or unrecognized and p flag si set
194                     // adds UnknownObject to list for validation purposes
195                     try {
196                         objs.add(PCEPObjectFactory.parse(bytesToPass, header));
197                     } catch (final PCEPDocumentedException e) {
198                         if (e.getError() == PCEPErrors.UNRECOGNIZED_OBJ_CLASS | e.getError() == PCEPErrors.UNRECOGNIZED_OBJ_TYPE
199                                 | e.getError() == PCEPErrors.NOT_SUPPORTED_OBJ_CLASS | e.getError() == PCEPErrors.NOT_SUPPORTED_OBJ_TYPE) {
200                             objs.add(new UnknownObject(header.processed, header.ignored, e.getError()));
201                         } else {
202                             throw e;
203                         }
204             }
205         }
206
207         return objs;
208     }
209
210     public static byte[] put(final List<PCEPObject> objects) {
211                 if (objects == null || objects.isEmpty())
212                     throw new IllegalArgumentException("List<PCEPObject> is mandatory and can't be empty.");
213
214                 final List<byte[]> listBytes = new ArrayList<byte[]>();
215
216                 byte[] bytes;
217                 int size = 0;
218                 for (final PCEPObject obj : objects) {
219                     bytes = put(obj);
220                     size += bytes.length;
221                     listBytes.add(bytes);
222                 }
223
224                 final byte[] retBytes = new byte[size];
225
226                 int offset = 0;
227                 for (final byte[] bs : listBytes) {
228                     ByteArray.copyWhole(bs, retBytes, offset);
229                     offset += bs.length;
230                 }
231
232                 return retBytes;
233     }
234
235     private static byte[] put(final PCEPObject obj) {
236
237                 byte[] objBody;
238                 ObjectClass objClass;
239                 int objType = 1;
240
241                 if (obj instanceof PCEPOpenObject) {
242                     objClass = PCEPObjectIdentifier.ObjectClass.OPEN;
243                 } else if (obj instanceof PCEPRequestParameterObject) {
244                     objClass = PCEPObjectIdentifier.ObjectClass.RP;
245                 } else if (obj instanceof PCEPNoPathObject) {
246                     objClass = PCEPObjectIdentifier.ObjectClass.NO_PATH;
247                 } else if (obj instanceof PCEPRequestedPathBandwidthObject) {
248                     objClass = PCEPObjectIdentifier.ObjectClass.BANDWIDTH;
249                 } else if (obj instanceof PCEPExistingPathBandwidthObject) {
250                     objClass = PCEPObjectIdentifier.ObjectClass.BANDWIDTH;
251                     objType = 2;
252                 } else if (obj instanceof PCEPMetricObject) {
253                     objClass = PCEPObjectIdentifier.ObjectClass.METRIC;
254                 } else if (obj instanceof PCEPEndPointsObject<?>) {
255                     objClass = PCEPObjectIdentifier.ObjectClass.END_POINTS;
256                     if (((PCEPEndPointsObject<?>) obj).getSourceAddress() instanceof IPv6Address) {
257                         objType = 2;
258                     } else if (!(((PCEPEndPointsObject<?>) obj).getSourceAddress() instanceof IPv4Address))
259                         throw new IllegalArgumentException("Unknown instance of Source Address.");
260
261                 } else if (obj instanceof PCEPP2MPEndPointsObject<?>) {
262                     objClass = PCEPObjectIdentifier.ObjectClass.END_POINTS;
263                     objType = 3;
264                     if (((PCEPP2MPEndPointsObject<?>) obj).getSourceAddress() instanceof IPv6Address) {
265                         objType = 4;
266                     } else if (!(((PCEPP2MPEndPointsObject<?>) obj).getSourceAddress() instanceof IPv4Address))
267                         throw new IllegalArgumentException("Unknown instance of Source Address.");
268
269                 } else if (obj instanceof PCEPUnreachedDestinationObject<?>) {
270                     objClass = PCEPObjectIdentifier.ObjectClass.UNREACHED_DESTINATION;
271                     if (((PCEPUnreachedDestinationObject<?>) obj).getUnreachedDestinations().get(0) instanceof IPv6Address) {
272                         objType = 2;
273                     } else if (!(((PCEPUnreachedDestinationObject<?>) obj).getUnreachedDestinations().get(0) instanceof IPv4Address))
274                         throw new IllegalArgumentException("Unknown instance of Source Address.");
275
276                 } else if (obj instanceof PCEPLspaObject) {
277                     objClass = PCEPObjectIdentifier.ObjectClass.LSPA;
278                 } else if (obj instanceof PCEPSvecObject) {
279                     objClass = PCEPObjectIdentifier.ObjectClass.SVEC;
280                     objType = 1;
281                 } else if (obj instanceof PCEPNotificationObject) {
282                     objClass = PCEPObjectIdentifier.ObjectClass.NOTIFICATION;
283                 } else if (obj instanceof PCEPErrorObject) {
284                     objClass = PCEPObjectIdentifier.ObjectClass.ERROR;
285                 } else if (obj instanceof PCEPCloseObject) {
286                     objClass = PCEPObjectIdentifier.ObjectClass.CLOSE;
287                 } else if (obj instanceof PCEPLoadBalancingObject) {
288                     objClass = PCEPObjectIdentifier.ObjectClass.LOAD_BALANCING;
289                 } else if (obj instanceof PCEPLspObject) {
290                     objClass = PCEPObjectIdentifier.ObjectClass.LSP;
291                 } else if (obj instanceof PCEPExplicitRouteObject) {
292                     objClass = PCEPObjectIdentifier.ObjectClass.ERO;
293                 } else if (obj instanceof PCEPReportedRouteObject) {
294                     objClass = PCEPObjectIdentifier.ObjectClass.RRO;
295                 } else if (obj instanceof PCEPIncludeRouteObject) {
296                     objClass = PCEPObjectIdentifier.ObjectClass.IRO;
297                 } else if (obj instanceof PCEPExcludeRouteObject) {
298                     objClass = PCEPObjectIdentifier.ObjectClass.XRO;
299                 } else if (obj instanceof PCEPObjectiveFunctionObject) {
300                     objClass = PCEPObjectIdentifier.ObjectClass.OBJCETIVE_FUNCTION;
301                 } else if (obj instanceof PCEPGlobalConstraintsObject) {
302                     objClass = PCEPObjectIdentifier.ObjectClass.GLOBAL_CONSTRAINTS;
303                 } else if (obj instanceof PCEPBranchNodeObject) {
304                     objClass = PCEPObjectIdentifier.ObjectClass.BRANCH_NODE;
305                     if (obj instanceof PCEPNonBranchNodeListObject) {
306                         objType = 2;
307                     } else if (!(obj instanceof PCEPBranchNodeListObject))
308                         throw new IllegalArgumentException("Unknown instance of PCEPBranchNodeObject.");
309                 } else if (obj instanceof PCEPSecondaryExplicitRouteObject) {
310                     objClass = PCEPObjectIdentifier.ObjectClass.SERO;
311                 } else if (obj instanceof PCEPSecondaryRecordRouteObject) {
312                     objClass = PCEPObjectIdentifier.ObjectClass.SRRO;
313                 } else
314                     throw new IllegalArgumentException("Unknown instance of PCEPObject.");
315
316                 final PCEPObjectParser objParserClass = MapOfParsers.getInstance().get(new PCEPObjectIdentifier(objClass, objType));
317                 objBody = objParserClass.put(obj);
318
319                 final byte[] objHeader = PCEPObjectHeader.putHeader(new PCEPObjectHeader(objClass.getIdentifier(), objType, objBody.length
320                         + PCEPObjectHeader.COMMON_OBJECT_HEADER_LENGTH, obj.isProcessed(), obj.isIgnored()));
321
322                 assert objBody.length % 4 == 0 : "Wrong length of PCEPObjectBody. Passed object has length: " + objBody.length + " that is not multiple of 4.";
323
324                 final byte[] retBytes = new byte[objHeader.length + objBody.length];
325                 ByteArray.copyWhole(objHeader, retBytes, 0);
326                 ByteArray.copyWhole(objBody, retBytes, PCEPObjectHeader.OBJ_BODY_OFFSET);
327
328                 return retBytes;
329     }
330 }