BUG-47: more subobject models
[bgpcep.git] / pcep / impl / src / main / java / org / opendaylight / protocol / pcep / impl / PCEPEROSubobjectParser.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.opendaylight.protocol.pcep.PCEPDeserializerException;
14 import org.opendaylight.protocol.pcep.impl.subobject.EROExplicitExclusionRouteSubobjectParser;
15 import org.opendaylight.protocol.pcep.impl.subobject.EROLabelSubobjectParser;
16 import org.opendaylight.protocol.pcep.impl.subobject.EROPathKeyWith128PCEIDSubobjectParser;
17 import org.opendaylight.protocol.pcep.impl.subobject.EROPathKeyWith32PCEIDSubobjectParser;
18 import org.opendaylight.protocol.pcep.impl.subobject.EROUnnumberedInterfaceSubobjectParser;
19 import org.opendaylight.protocol.pcep.subobject.EROAsNumberSubobject;
20 import org.opendaylight.protocol.pcep.subobject.EROExplicitExclusionRouteSubobject;
21 import org.opendaylight.protocol.pcep.subobject.EROLabelSubobject;
22 import org.opendaylight.protocol.pcep.subobject.EROPathKeyWith128PCEIDSubobject;
23 import org.opendaylight.protocol.pcep.subobject.EROPathKeyWith32PCEIDSubobject;
24 import org.opendaylight.protocol.pcep.subobject.EROUnnumberedInterfaceSubobject;
25 import org.opendaylight.protocol.pcep.subobject.ExplicitRouteSubobject;
26 import org.opendaylight.protocol.util.ByteArray;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * Parser for {@link org.opendaylight.protocol.pcep.PCEPSubobject PCEPSubobject}
32  */
33 public class PCEPEROSubobjectParser {
34
35         private static final Logger logger = LoggerFactory.getLogger(PCEPEROSubobjectParser.class);
36
37         /**
38          * Type identifier for {@link org.opendaylight.protocol.pcep.PCEPSubobject PCEPSubobject}
39          */
40         public enum PCEPSubobjectType {
41                 IPv4_PREFIX(1), IPv6_PREFIX(2), LABEL(3), UNNUMBERED_INTERFACE_ID(4), AS_NUMBER(32), EXRS(33), PROTECTION(37), PK_32(64), PK_128(65);
42
43                 private final int indicator;
44
45                 PCEPSubobjectType(final int indicator) {
46                         this.indicator = indicator;
47                 }
48
49                 public int getIndicator() {
50                         return this.indicator;
51                 }
52
53                 public static PCEPSubobjectType getFromInt(final int type) throws PCEPDeserializerException {
54
55                         for (final PCEPSubobjectType type_e : PCEPSubobjectType.values()) {
56                                 if (type_e.getIndicator() == type) {
57                                         return type_e;
58                                 }
59                         }
60
61                         throw new PCEPDeserializerException("Unknown Subobject type. Passed: " + type + "; Known: " + PCEPSubobjectType.values() + ".");
62                 }
63         }
64
65         /*
66          * Fields lengths in Bytes
67          */
68         public static final int TYPE_FLAG_F_LENGTH = 1;
69         public static final int LENGTH_F_LENGTH = 1;
70
71         /*
72          * Fields offsets in Bytes
73          */
74         public static final int TYPE_FLAG_F_OFFSET = 0;
75         public static final int LENGTH_F_OFFSET = TYPE_FLAG_F_OFFSET + TYPE_FLAG_F_LENGTH;
76         public static final int SO_CONTENTS_OFFSET = LENGTH_F_OFFSET + LENGTH_F_LENGTH;
77
78         public static List<ExplicitRouteSubobject> parse(final byte[] bytes) throws PCEPDeserializerException {
79                 if (bytes == null) {
80                         throw new IllegalArgumentException("Byte array is mandatory.");
81                 }
82
83                 final List<ExplicitRouteSubobject> subobjsList = new ArrayList<ExplicitRouteSubobject>();
84                 boolean loose_flag;
85                 PCEPSubobjectType type;
86                 byte[] soContentsBytes;
87                 int length;
88                 int offset = 0;
89
90                 while (offset < bytes.length) {
91
92                         loose_flag = ((bytes[offset + TYPE_FLAG_F_OFFSET] & (1 << 7)) != 0) ? true : false;
93                         length = ByteArray.bytesToInt(ByteArray.subByte(bytes, offset + LENGTH_F_OFFSET, LENGTH_F_LENGTH));
94
95                         type = PCEPSubobjectType.getFromInt((bytes[offset + TYPE_FLAG_F_OFFSET] & 0xff) & ~(1 << 7));
96
97                         if (length > bytes.length - offset) {
98                                 throw new PCEPDeserializerException("Wrong length specified. Passed: " + length + "; Expected: <= "
99                                                 + (bytes.length - offset));
100                         }
101
102                         soContentsBytes = new byte[length - SO_CONTENTS_OFFSET];
103                         System.arraycopy(bytes, offset + SO_CONTENTS_OFFSET, soContentsBytes, 0, length - SO_CONTENTS_OFFSET);
104
105                         logger.debug("Attempt to parse subobject from bytes: {}", ByteArray.bytesToHexString(soContentsBytes));
106                         final ExplicitRouteSubobject subObj = parseSpecificSubobject(type, soContentsBytes, loose_flag);
107                         logger.debug("Subobject was parsed. {}", subObj);
108
109                         subobjsList.add(subObj);
110
111                         offset += length;
112                 }
113
114                 return subobjsList;
115         }
116
117         public static byte[] put(final List<ExplicitRouteSubobject> objsToSerialize) {
118                 final List<byte[]> bytesList = new ArrayList<byte[]>(objsToSerialize.size());
119
120                 int length = 0;
121                 for (final ExplicitRouteSubobject obj : objsToSerialize) {
122                         final byte[] bytes = put(obj);
123                         length += bytes.length;
124                         bytesList.add(bytes);
125                 }
126
127                 final byte[] retBytes = new byte[length];
128
129                 int offset = 0;
130                 for (final byte[] bytes : bytesList) {
131                         System.arraycopy(bytes, 0, retBytes, offset, bytes.length);
132                         offset += bytes.length;
133                 }
134
135                 return retBytes;
136         }
137
138         public static byte[] put(final ExplicitRouteSubobject objToSerialize) {
139                 int typeIndicator = 0;
140
141                 byte[] soContentsBytes = null;
142
143                 // if (objToSerialize instanceof EROIPPrefixSubobject<?>
144                 // && ((EROIPPrefixSubobject<?>) objToSerialize).getPrefix() instanceof IPv4Prefix) {
145                 // typeIndicator = PCEPSubobjectType.IPv4_PREFIX.getIndicator();
146                 // // soContentsBytes = EROIpPrefixSubobjectParser.put(objToSerialize);
147                 // } else if (objToSerialize instanceof EROIPPrefixSubobject<?>
148                 // && ((EROIPPrefixSubobject<?>) objToSerialize).getPrefix() instanceof IPv6Prefix) {
149                 // typeIndicator = PCEPSubobjectType.IPv6_PREFIX.getIndicator();
150                 // // soContentsBytes = EROIPv6PrefixSubobjectParser.put(objToSerialize);
151                 // } else
152                 if (objToSerialize instanceof EROAsNumberSubobject) {
153                         typeIndicator = PCEPSubobjectType.AS_NUMBER.getIndicator();
154                         // soContentsBytes = EROAsNumberSubobjectParser.put(objToSerialize);
155                 } else if (objToSerialize instanceof EROUnnumberedInterfaceSubobject) {
156                         typeIndicator = PCEPSubobjectType.UNNUMBERED_INTERFACE_ID.getIndicator();
157                         soContentsBytes = EROUnnumberedInterfaceSubobjectParser.put(objToSerialize);
158                 } else if (objToSerialize instanceof EROLabelSubobject) {
159                         typeIndicator = PCEPSubobjectType.LABEL.getIndicator();
160                         soContentsBytes = EROLabelSubobjectParser.put((EROLabelSubobject) objToSerialize);
161                 } else if (objToSerialize instanceof EROExplicitExclusionRouteSubobject) {
162                         typeIndicator = PCEPSubobjectType.EXRS.getIndicator();
163                         soContentsBytes = EROExplicitExclusionRouteSubobjectParser.put((EROExplicitExclusionRouteSubobject) objToSerialize);
164                 } else if (objToSerialize instanceof EROPathKeyWith32PCEIDSubobject) {
165                         typeIndicator = PCEPSubobjectType.PK_32.getIndicator();
166                         soContentsBytes = EROPathKeyWith32PCEIDSubobjectParser.put((EROPathKeyWith32PCEIDSubobject) objToSerialize);
167                 } else if (objToSerialize instanceof EROPathKeyWith128PCEIDSubobject) {
168                         typeIndicator = PCEPSubobjectType.PK_128.getIndicator();
169                         soContentsBytes = EROPathKeyWith128PCEIDSubobjectParser.put((EROPathKeyWith128PCEIDSubobject) objToSerialize);
170                 } else {
171                         throw new IllegalArgumentException("Unknown instance of PCEPSubobject. Passed: " + objToSerialize.getClass() + ".");
172                 }
173
174                 final byte[] bytes = new byte[SO_CONTENTS_OFFSET + soContentsBytes.length];
175
176                 bytes[TYPE_FLAG_F_OFFSET] = (byte) (ByteArray.cutBytes(ByteArray.intToBytes(typeIndicator), (Integer.SIZE / 8) - TYPE_FLAG_F_LENGTH)[0] | (objToSerialize.isLoose() ? 1 << 7
177                                 : 0));
178                 bytes[LENGTH_F_OFFSET] = ByteArray.cutBytes(ByteArray.intToBytes(soContentsBytes.length + SO_CONTENTS_OFFSET), (Integer.SIZE / 8)
179                                 - LENGTH_F_LENGTH)[0];
180
181                 System.arraycopy(soContentsBytes, 0, bytes, SO_CONTENTS_OFFSET, soContentsBytes.length);
182
183                 return bytes;
184         }
185
186         private static ExplicitRouteSubobject parseSpecificSubobject(final PCEPSubobjectType type, final byte[] soContentsBytes,
187                         final boolean loose_flag) throws PCEPDeserializerException {
188
189                 switch (type) {
190                 case IPv4_PREFIX:
191                         // return EROIpPrefixSubobjectParser.parse(soContentsBytes, loose_flag);
192                 case IPv6_PREFIX:
193                         // return EROIPv6PrefixSubobjectParser.parse(soContentsBytes, loose_flag);
194                 case UNNUMBERED_INTERFACE_ID:
195                         return EROUnnumberedInterfaceSubobjectParser.parse(soContentsBytes, loose_flag);
196                 case AS_NUMBER:
197                         // return EROAsNumberSubobjectParser.parse(soContentsBytes, loose_flag);
198                 case LABEL:
199                         return EROLabelSubobjectParser.parse(soContentsBytes, loose_flag);
200                 case EXRS:
201                         return EROExplicitExclusionRouteSubobjectParser.parse(soContentsBytes, loose_flag);
202                 case PK_32:
203                         return EROPathKeyWith32PCEIDSubobjectParser.parse(soContentsBytes, loose_flag);
204                 case PK_128:
205                         return EROPathKeyWith128PCEIDSubobjectParser.parse(soContentsBytes, loose_flag);
206                 default:
207                         throw new PCEPDeserializerException("Unknown Subobject type. Passed: " + type + ".");
208                 }
209         }
210 }