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