cc1a168b599b417dd4a516e5415c9f9dd553c859
[bgpcep.git] / bgp / parser-impl / src / main / java / org / opendaylight / protocol / bgp / parser / impl / message / update / LinkStateParser.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.bgp.parser.impl.message.update;
9
10 import java.math.BigInteger;
11 import java.util.Arrays;
12 import java.util.HashMap;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Map.Entry;
16 import java.util.Set;
17
18 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
19 import org.opendaylight.protocol.bgp.parser.impl.ByteList;
20 import org.opendaylight.protocol.concepts.Ipv4Util;
21 import org.opendaylight.protocol.concepts.Ipv6Util;
22 import org.opendaylight.protocol.util.ByteArray;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.AdministrativeGroup;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.AreaIdentifier;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.DomainIdentifier;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.ExtendedRouteTag;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.Identifier;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.IgpBits.UpDown;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.Ipv4InterfaceIdentifier;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.Ipv4RouterIdentifier;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.Ipv6InterfaceIdentifier;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.Ipv6RouterIdentifier;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.IsisAreaIdentifier;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.LinkProtectionType;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.MplsProtocolMask;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.NlriType;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.NodeFlagBits;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.NodeIdentifier;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.OspfInterfaceIdentifier;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.OspfRouteType;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.ProtocolId;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.RouteDistinguisher;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.RouteTag;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.SharedRiskLinkGroup;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.TopologyIdentifier;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.isis.lan.identifier.IsIsRouterIdentifier;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.isis.lan.identifier.IsIsRouterIdentifierBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.link.state.UnreservedBandwidthBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.CLinkstateDestination;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.CLinkstateDestinationBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.c.linkstate.destination.LinkDescriptors;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.c.linkstate.destination.LinkDescriptorsBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.c.linkstate.destination.LocalNodeDescriptors;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.c.linkstate.destination.LocalNodeDescriptorsBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.c.linkstate.destination.PrefixDescriptors;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.c.linkstate.destination.PrefixDescriptorsBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.c.linkstate.destination.RemoteNodeDescriptors;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.CRouterIdentifier;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.CIsisNodeBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.CIsisPseudonodeBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.COspfNodeBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.COspfPseudonodeBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.c.isis.node.IsisNodeBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.c.isis.pseudonode.IsisPseudonodeBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.c.ospf.node.OspfNodeBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.c.ospf.pseudonode.OspfPseudonodeBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.prefix.state.IgpBitsBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.update.path.attributes.LinkstatePathAttribute;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.update.path.attributes.LinkstatePathAttributeBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.update.path.attributes.linkstate.path.attribute.link.state.attribute.LinkAttributes;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.update.path.attributes.linkstate.path.attribute.link.state.attribute.LinkAttributesBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.update.path.attributes.linkstate.path.attribute.link.state.attribute.NodeAttributes;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.update.path.attributes.linkstate.path.attribute.link.state.attribute.NodeAttributesBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.update.path.attributes.linkstate.path.attribute.link.state.attribute.PrefixAttributes;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.update.path.attributes.linkstate.path.attribute.link.state.attribute.PrefixAttributesBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.MplsLabeledVpnSubsequentAddressFamily;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.SubsequentAddressFamily;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nps.concepts.rev130930.Bandwidth;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nps.concepts.rev130930.IgpMetric;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nps.concepts.rev130930.IsoSystemIdentifier;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nps.concepts.rev130930.Metric;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nps.concepts.rev130930.TeMetric;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
88
89 import com.google.common.base.Charsets;
90 import com.google.common.collect.Lists;
91 import com.google.common.collect.Sets;
92 import com.google.common.primitives.UnsignedBytes;
93
94 /**
95  * Parser for Link State information.
96  * 
97  * @see <a href="http://tools.ietf.org/html/draft-gredler-idr-ls-distribution-01">BGP-LS draft</a>
98  */
99 public class LinkStateParser {
100
101         private static final Logger logger = LoggerFactory.getLogger(LinkStateParser.class);
102
103         private static final int TYPE_LENGTH = 2;
104
105         private static final int LENGTH_SIZE = 2;
106
107         private static final int ROUTE_DISTINGUISHER_LENGTH = 8;
108
109         private static final int PROTOCOL_ID_LENGTH = 1;
110
111         private static final int IDENTIFIER_LENGTH = 8;
112
113         private static final Set<Integer> nodeTlvs = Sets.newHashSet(263, 1024, 1025, 1026, 1027, 1028, 1029);
114
115         private static final Set<Integer> linkTlvs = Sets.newHashSet(1028, 1029, 1030, 1031, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095,
116                         1096, 1097, 1098);
117
118         private static final Set<Integer> prefixTlvs = Sets.newHashSet(1152, 1153, 1154, 1155, 1156, 1157);
119
120         private LinkStateParser() {
121         }
122
123         /**
124          * Parses common parts for Link State Nodes, Links and Prefixes, that includes protocol ID and identifier tlv.
125          * 
126          * @param reachable
127          * @param safi
128          * @param bytes
129          * @return BGPLinkMP or BGPNodeMP
130          * @throws BGPParsingException
131          */
132         protected static CLinkstateDestination parseLSNlri(final Class<? extends SubsequentAddressFamily> safi, final byte[] bytes)
133                         throws BGPParsingException {
134                 if (bytes.length == 0) {
135                         return null;
136                 }
137                 int byteOffset = 0;
138
139                 final CLinkstateDestinationBuilder builder = new CLinkstateDestinationBuilder();
140
141                 while (byteOffset != bytes.length) {
142                         final NlriType type = NlriType.forValue(ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH)));
143                         builder.setNlriType(type);
144
145                         byteOffset += TYPE_LENGTH;
146                         // length means total length of the tlvs including route distinguisher not including the type field
147                         final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
148                         byteOffset += LENGTH_SIZE;
149                         RouteDistinguisher distinguisher = null;
150                         if (safi == MplsLabeledVpnSubsequentAddressFamily.class) {
151                                 // this parses route distinguisher
152                                 distinguisher = new RouteDistinguisher(BigInteger.valueOf(ByteArray.bytesToLong(ByteArray.subByte(bytes, byteOffset,
153                                                 ROUTE_DISTINGUISHER_LENGTH))));
154                                 builder.setDistinguisher(distinguisher);
155                                 byteOffset += ROUTE_DISTINGUISHER_LENGTH;
156                         }
157                         // parse source protocol
158                         final ProtocolId sp = ProtocolId.forValue(ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, PROTOCOL_ID_LENGTH)));
159                         byteOffset += PROTOCOL_ID_LENGTH;
160                         builder.setProtocolId(sp);
161
162                         // parse identifier
163                         final Identifier identifier = new Identifier(BigInteger.valueOf(ByteArray.bytesToLong(ByteArray.subByte(bytes, byteOffset,
164                                         IDENTIFIER_LENGTH))));
165                         byteOffset += IDENTIFIER_LENGTH;
166                         builder.setIdentifier(identifier);
167
168                         // if we are dealing with linkstate nodes/links, parse local node descriptor
169                         NodeIdentifier localDescriptor = null;
170                         int locallength = 0;
171                         final int localtype = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
172                         byteOffset += TYPE_LENGTH;
173                         locallength = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
174                         byteOffset += LENGTH_SIZE;
175                         if (localtype == 256) {
176                                 localDescriptor = parseNodeDescriptors(ByteArray.subByte(bytes, byteOffset, locallength));
177                         }
178                         byteOffset += locallength;
179                         builder.setLocalNodeDescriptors((LocalNodeDescriptors) localDescriptor);
180                         final int restLength = length - ((safi == MplsLabeledVpnSubsequentAddressFamily.class) ? ROUTE_DISTINGUISHER_LENGTH : 0)
181                                         - PROTOCOL_ID_LENGTH - IDENTIFIER_LENGTH - TYPE_LENGTH - LENGTH_SIZE - locallength;
182                         logger.debug("Restlength {}", restLength);
183                         switch (type) {
184                         case Link:
185                                 parseLink(builder, ByteArray.subByte(bytes, byteOffset, restLength));
186                                 break;
187                         case Ipv4Prefix:
188                         case Ipv6Prefix:
189                                 builder.setPrefixDescriptors(parsePrefixDescriptors(localDescriptor, ByteArray.subByte(bytes, byteOffset, restLength)));
190                                 break;
191                         case Node:
192                                 // node nlri is already parsed as it contains only the common fields for node and link nlri
193                                 break;
194                         }
195                         byteOffset += restLength;
196                 }
197                 return builder.build();
198         }
199
200         public static boolean verifyLink(final Set<Integer> keys) {
201                 for (final Integer i : keys) {
202                         if (!linkTlvs.contains(i)) {
203                                 logger.warn("Invalid link attribute {}", i);
204                                 return false;
205                         }
206                 }
207                 return true;
208         }
209
210         public static boolean verifyNode(final Set<Integer> keys) {
211                 for (final Integer i : keys) {
212                         if (!nodeTlvs.contains(i)) {
213                                 logger.warn("Invalid node attribute {}", i);
214                                 return false;
215                         }
216                 }
217                 return true;
218         }
219
220         public static boolean verifyPrefix(final Set<Integer> keys) {
221                 for (final Integer i : keys) {
222                         if (!prefixTlvs.contains(i)) {
223                                 logger.warn("Invalid prefix attribute {}", i);
224                                 return false;
225                         }
226                 }
227                 return true;
228         }
229
230         private static NodeIdentifier parseLink(final CLinkstateDestinationBuilder builder, final byte[] bytes) throws BGPParsingException {
231                 int byteOffset = 0;
232                 final int type = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
233                 byteOffset += TYPE_LENGTH;
234                 final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
235                 byteOffset += LENGTH_SIZE;
236                 final NodeIdentifier remote = null;
237                 if (type == 257) {
238                         builder.setRemoteNodeDescriptors((RemoteNodeDescriptors) parseNodeDescriptors(ByteArray.subByte(bytes, byteOffset, length)));
239                         byteOffset += length;
240                 }
241                 builder.setLinkDescriptors(parseLinkDescriptors(ByteArray.subByte(bytes, byteOffset, bytes.length - byteOffset)));
242                 return remote;
243         }
244
245         private static LinkDescriptors parseLinkDescriptors(final byte[] bytes) throws BGPParsingException {
246                 int byteOffset = 0;
247                 final LinkDescriptorsBuilder builder = new LinkDescriptorsBuilder();
248                 while (byteOffset != bytes.length) {
249                         final int type = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
250                         byteOffset += TYPE_LENGTH;
251                         final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
252                         byteOffset += LENGTH_SIZE;
253                         final byte[] value = ByteArray.subByte(bytes, byteOffset, length);
254                         logger.debug("Parsing Link Descriptor: {}", Arrays.toString(value));
255                         switch (type) {
256                         case 258:
257                                 builder.setLinkLocalIdentifier(ByteArray.subByte(value, 0, 4));
258                                 builder.setLinkRemoteIdentifier(ByteArray.subByte(value, 4, 4));
259                                 logger.trace("Parsed link local {} remote {} Identifiers.", builder.getLinkLocalIdentifier(),
260                                                 builder.getLinkRemoteIdentifier());
261                                 break;
262                         case 259:
263                                 final Ipv4InterfaceIdentifier lipv4 = new Ipv4InterfaceIdentifier(Ipv4Util.addressForBytes(value));
264                                 builder.setIpv4InterfaceAddress(lipv4);
265                                 logger.trace("Parsed IPv4 interface address {}.", lipv4);
266                                 break;
267                         case 260:
268                                 final Ipv4InterfaceIdentifier ripv4 = new Ipv4InterfaceIdentifier(Ipv4Util.addressForBytes(value));
269                                 builder.setIpv4NeighborAddress(ripv4);
270                                 logger.trace("Parsed IPv4 neighbor address {}.", ripv4);
271                                 break;
272                         case 261:
273                                 final Ipv6InterfaceIdentifier lipv6 = new Ipv6InterfaceIdentifier(Ipv6Util.addressForBytes(value));
274                                 builder.setIpv6InterfaceAddress(lipv6);
275                                 logger.trace("Parsed IPv6 interface address {}.", lipv6);
276                                 break;
277                         case 262:
278                                 final Ipv6InterfaceIdentifier ripv6 = new Ipv6InterfaceIdentifier(Ipv6Util.addressForBytes(value));
279                                 builder.setIpv6NeighborAddress(ripv6);
280                                 logger.trace("Parsed IPv6 neighbor address {}.", ripv6);
281                                 break;
282                         case 263:
283                                 final TopologyIdentifier topId = new TopologyIdentifier(ByteArray.bytesToInt(value) & 0x3fff);
284                                 builder.setMultiTopologyId(topId);
285                                 logger.trace("Parsed topology identifier {}.", topId);
286                                 break;
287                         default:
288                                 throw new BGPParsingException("Link Descriptor not recognized, type: " + type);
289                         }
290                         byteOffset += length;
291                 }
292                 logger.debug("Finished parsing Link descriptors.");
293                 return builder.build();
294         }
295
296         private static NodeIdentifier parseNodeDescriptors(final byte[] bytes) throws BGPParsingException {
297                 int byteOffset = 0;
298                 AsNumber asnumber = null;
299                 DomainIdentifier bgpId = null;
300                 AreaIdentifier ai = null;
301                 CRouterIdentifier routerId = null;
302                 while (byteOffset != bytes.length) {
303                         final int type = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
304                         byteOffset += TYPE_LENGTH;
305                         final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
306                         byteOffset += LENGTH_SIZE;
307                         final byte[] value = ByteArray.subByte(bytes, byteOffset, length);
308                         logger.debug("Parsing Node Descriptor: {}", Arrays.toString(value));
309                         switch (type) {
310                         case 512:
311                                 asnumber = new AsNumber(ByteArray.bytesToLong(value));
312                                 logger.trace("Parsed AS number {}", asnumber);
313                                 break;
314                         case 513:
315                                 bgpId = new DomainIdentifier(value);
316                                 logger.trace("Parsed bgpId {}", bgpId);
317                                 break;
318                         case 514:
319                                 ai = new AreaIdentifier(value);
320                                 logger.trace("Parsed area identifier {}", ai);
321                                 break;
322                         case 515:
323                                 if (value.length == 6) {
324                                         routerId = new CIsisNodeBuilder().setIsisNode(
325                                                         new IsisNodeBuilder().setIsoSystemId(new IsoSystemIdentifier(ByteArray.subByte(value, 0, 6))).build()).build();
326                                 } else if (value.length == 7) {
327                                         if (value[6] == 0) {
328                                                 logger.warn("PSN octet is 0. Ignoring System ID.");
329                                                 routerId = new CIsisNodeBuilder().setIsisNode(
330                                                                 new IsisNodeBuilder().setIsoSystemId(new IsoSystemIdentifier(ByteArray.subByte(value, 0, 6))).build()).build();
331                                                 break;
332                                         } else {
333                                                 final IsIsRouterIdentifier iri = new IsIsRouterIdentifierBuilder().setIsoSystemId(
334                                                                 new IsoSystemIdentifier(ByteArray.subByte(value, 0, 6))).build();
335                                                 routerId = new CIsisPseudonodeBuilder().setIsisPseudonode(
336                                                                 new IsisPseudonodeBuilder().setIsIsRouterIdentifier(iri).setPsn((short) UnsignedBytes.toInt(value[6])).build()).build();
337                                         }
338                                 } else if (value.length == 4) {
339                                         routerId = new COspfNodeBuilder().setOspfNode(
340                                                         new OspfNodeBuilder().setOspfRouterId(ByteArray.subByte(value, 0, 4)).build()).build();
341                                 } else if (value.length == 8) {
342                                         final byte[] o = ByteArray.subByte(value, 0, 4); // FIXME: OSPFv3 vs OSPFv2
343                                         final OspfInterfaceIdentifier a = new OspfInterfaceIdentifier(ByteArray.subByte(value, 4, 4));
344                                         routerId = new COspfPseudonodeBuilder().setOspfPseudonode(
345                                                         new OspfPseudonodeBuilder().setOspfRouterId(o).setLanInterface(a).build()).build();
346                                 }
347                                 logger.trace("Parsed Router Identifier {}", routerId);
348                                 break;
349                         default:
350                                 throw new BGPParsingException("Node Descriptor not recognized, type: " + type);
351                         }
352                         byteOffset += length;
353                 }
354                 logger.debug("Finished parsing Node descriptors.");
355                 return new LocalNodeDescriptorsBuilder().setAsNumber(asnumber).setDomainId(bgpId).setAreaId(ai).setCRouterIdentifier(routerId).build();
356         }
357
358         private static PrefixDescriptors parsePrefixDescriptors(final NodeIdentifier localDescriptor, final byte[] bytes)
359                         throws BGPParsingException {
360                 int byteOffset = 0;
361                 final PrefixDescriptorsBuilder builder = new PrefixDescriptorsBuilder();
362                 while (byteOffset != bytes.length) {
363                         final int type = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
364                         byteOffset += TYPE_LENGTH;
365                         final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
366                         byteOffset += LENGTH_SIZE;
367                         final byte[] value = ByteArray.subByte(bytes, byteOffset, length);
368                         logger.trace("Parsing Prefix Descriptor: {}", Arrays.toString(value));
369                         switch (type) {
370                         case 263:
371                                 final TopologyIdentifier topologyId = new TopologyIdentifier(ByteArray.bytesToInt(value) & 0x3fff);
372                                 builder.setMultiTopologyId(topologyId);
373                                 logger.trace("Parsed Topology Identifier: {}", topologyId);
374                                 break;
375                         case 264:
376                                 final int rt = ByteArray.bytesToInt(value);
377                                 final OspfRouteType routeType = OspfRouteType.forValue(rt);
378                                 if (routeType == null)
379                                         throw new BGPParsingException("Unknown OSPF Route Type: " + rt);
380                                 builder.setOspfRouteType(routeType);
381                                 logger.trace("Parser RouteType: {}", routeType);
382                                 break;
383                         case 265:
384                                 IpPrefix prefix = null;
385                                 final int prefixLength = UnsignedBytes.toInt(value[0]);
386                                 final int size = prefixLength / 8 + ((prefixLength % 8 == 0) ? 0 : 1);
387                                 if (size != value.length - 1) {
388                                         logger.debug("Expected length {}, actual length {}.", size, value.length - 1);
389                                         throw new BGPParsingException("Illegal length of IP reachability TLV: " + (value.length - 1));
390                                 }
391                                 if (size == 4)
392                                         prefix = new IpPrefix(Ipv4Util.prefixForBytes(ByteArray.subByte(value, 1, size), prefixLength));
393                                 else
394                                         prefix = new IpPrefix(Ipv6Util.prefixForBytes(ByteArray.subByte(value, 1, size), prefixLength));
395                                 builder.setIpReachabilityInformation(prefix);
396                                 logger.trace("Parsed IP reachability info: {}", prefix);
397                                 break;
398                         default:
399                                 throw new BGPParsingException("Prefix Descriptor not recognized, type: " + type);
400                         }
401                         byteOffset += length;
402                 }
403                 logger.debug("Finished parsing Prefix descriptors.");
404                 return builder.build();
405         }
406
407         protected static LinkstatePathAttribute parseLinkState(final byte[] bytes) throws BGPParsingException {
408                 final Map<Integer, ByteList> map = new HashMap<Integer, ByteList>();
409                 int byteOffset = 0;
410                 while (byteOffset != bytes.length) {
411                         final int type = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
412                         byteOffset += TYPE_LENGTH;
413                         final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
414                         byteOffset += LENGTH_SIZE;
415                         final byte[] value = ByteArray.subByte(bytes, byteOffset, length);
416                         ByteList values = map.containsKey(type) ? values = map.get(type) : new ByteList();
417                         values.add(value);
418                         map.put(type, values);
419                         byteOffset += length;
420                 }
421                 final LinkstatePathAttributeBuilder builder = new LinkstatePathAttributeBuilder();
422                 if (verifyLink(map.keySet())) {
423                         builder.setLinkStateAttribute(parseLinkAttributes(map));
424                 } else if (verifyNode(map.keySet())) {
425                         builder.setLinkStateAttribute(parseNodeAttributes(map));
426                 } else if (verifyPrefix(map.keySet())) {
427                         builder.setLinkStateAttribute(parsePrefixAttributes(map));
428                 }
429                 return builder.build();
430         }
431
432         /**
433          * Parse Link Attributes.
434          * 
435          * @param attributes key is the tlv type and value is the value of the tlv
436          * @return {@link LinkAttributes}
437          * @throws BGPParsingException if a link attribute is not recognized
438          */
439         public static LinkAttributes parseLinkAttributes(final Map<Integer, ByteList> attributes) throws BGPParsingException {
440
441                 final LinkAttributesBuilder builder = new LinkAttributesBuilder();
442                 for (final Entry<Integer, ByteList> entry : attributes.entrySet()) {
443                         logger.debug("Link attribute TLV {}", entry.getKey());
444
445                         for (final byte[] value : entry.getValue().getBytes()) {
446
447                                 switch (entry.getKey()) {
448                                 case 1028:
449                                         final Ipv4RouterIdentifier lipv4 = new Ipv4RouterIdentifier(Ipv4Util.addressForBytes(value));
450                                         builder.setLocalIpv4RouterId(lipv4);
451                                         logger.trace("Parsed IPv4 Router-ID of local node: {}", lipv4);
452                                         break;
453                                 case 1029:
454                                         final Ipv6RouterIdentifier lipv6 = new Ipv6RouterIdentifier(Ipv6Util.addressForBytes(value));
455                                         builder.setLocalIpv6RouterId(lipv6);
456                                         logger.trace("Parsed IPv6 Router-ID of local node: {}", lipv6);
457                                         break;
458                                 case 1030:
459                                         final Ipv4RouterIdentifier ripv4 = new Ipv4RouterIdentifier(Ipv4Util.addressForBytes(value));
460                                         builder.setRemoteIpv4RouterId(ripv4);
461                                         logger.trace("Parsed IPv4 Router-ID of remote node: {}", ripv4);
462                                         break;
463                                 case 1031:
464                                         final Ipv6RouterIdentifier ripv6 = new Ipv6RouterIdentifier(Ipv6Util.addressForBytes(value));
465                                         builder.setRemoteIpv6RouterId(ripv6);
466                                         logger.trace("Parsed IPv6 Router-ID of remote node: {}", ripv6);
467                                         break;
468                                 case 1088:
469                                         builder.setAdminGroup(new AdministrativeGroup(ByteArray.bytesToLong(value)));
470                                         logger.trace("Parsed Administrative Group {}", builder.getAdminGroup());
471                                         break;
472                                 case 1089:
473                                         builder.setMaxLinkBandwidth(new Bandwidth(value));
474                                         logger.trace("Parsed Max Bandwidth {}", builder.getMaxLinkBandwidth());
475                                         break;
476                                 case 1090:
477                                         builder.setMaxReservableBandwidth(new Bandwidth(value));
478                                         logger.trace("Parsed Max Reservable Bandwidth {}", builder.getMaxReservableBandwidth());
479                                         break;
480                                 case 1091:
481                                         int index = 0;
482                                         final List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.link.state.UnreservedBandwidth> unreservedBandwidth = Lists.newArrayList();
483                                         for (int i = 0; i < 8; i++) {
484                                                 unreservedBandwidth.add(new UnreservedBandwidthBuilder().setBandwidth(
485                                                                 new Bandwidth(ByteArray.subByte(value, index, 4))).setPriority((short) i).build());
486                                                 index += 4;
487                                         }
488                                         builder.setUnreservedBandwidth(unreservedBandwidth);
489                                         logger.trace("Parsed Unreserved Bandwidth {}", builder.getUnreservedBandwidth());
490                                         break;
491                                 case 1092:
492                                         builder.setTeMetric(new TeMetric(ByteArray.bytesToLong(value)));
493                                         logger.trace("Parsed Metric {}", builder.getTeMetric());
494                                         break;
495                                 case 1093:
496                                         final LinkProtectionType lpt = LinkProtectionType.forValue(UnsignedBytes.toInt(value[0]));
497                                         if (lpt == null)
498                                                 throw new BGPParsingException("Link Protection Type not recognized: " + UnsignedBytes.toInt(value[0]));
499                                         builder.setLinkProtection(lpt);
500                                         logger.trace("Parsed Link Protection Type {}", lpt);
501                                         break;
502                                 case 1094:
503                                         final boolean[] bits = ByteArray.parseBits(value[0]);
504                                         builder.setMplsProtocol(new MplsProtocolMask(bits[0], bits[1]));
505                                         logger.trace("Parsed MPLS Protocols: {}", builder.getMplsProtocol());
506                                         break;
507                                 case 1095:
508                                         builder.setMetric(new Metric(ByteArray.bytesToLong(value)));
509                                         logger.trace("Parsed Metric {}", builder.getMetric());
510                                         break;
511                                 case 1096:
512                                         int i = 0;
513                                         final List<SharedRiskLinkGroup> sharedRiskLinkGroups = Lists.newArrayList();
514                                         while (i != value.length) {
515                                                 sharedRiskLinkGroups.add(new SharedRiskLinkGroup(ByteArray.bytesToLong(ByteArray.subByte(value, i, 4))));
516                                                 i += 4;
517                                         }
518                                         builder.setSharedRiskLinkGroups(sharedRiskLinkGroups);
519                                         logger.trace("Parsed Shared Risk Link Groups {}", Arrays.toString(sharedRiskLinkGroups.toArray()));
520                                         break;
521                                 case 1097:
522                                         final byte[] opaque = value;
523                                         logger.trace("Parsed Opaque value : {}", Arrays.toString(opaque));
524                                         break;
525                                 case 1098:
526                                         final String name = new String(value, Charsets.US_ASCII);
527                                         builder.setLinkName(name);
528                                         logger.trace("Parsed Link Name : ", name);
529                                         break;
530                                 default:
531                                         throw new BGPParsingException("Link Attribute not recognized, type: " + entry.getKey());
532                                 }
533                         }
534                 }
535                 logger.debug("Finished parsing Link Attributes.");
536                 return builder.build();
537         }
538
539         /**
540          * Parse Node Attributes.
541          * 
542          * @param attributes key is the tlv type and value is the value of the tlv
543          * @return {@link NodeAttributes}
544          * @throws BGPParsingException if a node attribute is not recognized
545          */
546         public static NodeAttributes parseNodeAttributes(final Map<Integer, ByteList> attributes) throws BGPParsingException {
547                 final List<TopologyIdentifier> topologyMembership = Lists.newArrayList();
548                 final List<IsisAreaIdentifier> areaMembership = Lists.newArrayList();
549                 final NodeAttributesBuilder builder = new NodeAttributesBuilder();
550                 for (final Entry<Integer, ByteList> entry : attributes.entrySet()) {
551                         logger.debug("Node attribute TLV {}", entry.getKey());
552                         for (final byte[] value : entry.getValue().getBytes()) {
553                                 switch (entry.getKey()) {
554                                 case 263:
555                                         int i = 0;
556                                         while (i != value.length) {
557                                                 final TopologyIdentifier topId = new TopologyIdentifier(ByteArray.bytesToInt(ByteArray.subByte(value, i, 2)) & 0x3fff);
558                                                 topologyMembership.add(topId);
559                                                 logger.trace("Parsed Topology Identifier: {}", topId);
560                                                 i += 2;
561                                         }
562                                         break;
563                                 case 1024:
564                                         final boolean[] flags = ByteArray.parseBits(value[0]);
565                                         builder.setNodeFlags(new NodeFlagBits(flags[0], flags[1], flags[2], flags[3]));
566                                         logger.trace("Parsed External bit {}, area border router {}.", flags[2], flags[3]);
567                                         break;
568                                 case 1025:
569                                         logger.debug("Ignoring opaque value: {}.", Arrays.toString(value));
570                                         break;
571                                 case 1026:
572                                         builder.setDynamicHostname(new String(value, Charsets.US_ASCII));
573                                         logger.trace("Parsed Node Name {}", builder.getDynamicHostname());
574                                         break;
575                                 case 1027:
576                                         final IsisAreaIdentifier ai = new IsisAreaIdentifier(value);
577                                         areaMembership.add(ai);
578                                         logger.trace("Parsed AreaIdentifier {}", ai);
579                                         break;
580                                 case 1028:
581                                         final Ipv4RouterIdentifier ip4 = new Ipv4RouterIdentifier(Ipv4Util.addressForBytes(value));
582                                         builder.setIpv4RouterId(ip4);
583                                         logger.trace("Parsed IPv4 Router Identifier {}", ip4);
584                                         break;
585                                 case 1029:
586                                         final Ipv6RouterIdentifier ip6 = new Ipv6RouterIdentifier(Ipv6Util.addressForBytes(value));
587                                         builder.setIpv6RouterId(ip6);
588                                         logger.trace("Parsed IPv6 Router Identifier {}", ip6);
589                                         break;
590                                 default:
591                                         throw new BGPParsingException("Node Attribute not recognized, type: " + entry.getKey());
592                                 }
593                         }
594                 }
595                 builder.setTopologyIdentifier(topologyMembership);
596                 builder.setIsisAreaId(areaMembership);
597                 logger.debug("Finished parsing Node Attributes.");
598                 return builder.build();
599         }
600
601         /**
602          * Parse prefix attributes.
603          * 
604          * @param attributes key is the tlv type and value are the value bytes of the tlv
605          * @return {@link PrefixAttributes}
606          * @throws BGPParsingException if some prefix attributes is not recognized
607          */
608         public static PrefixAttributes parsePrefixAttributes(final Map<Integer, ByteList> attributes) throws BGPParsingException {
609                 final PrefixAttributesBuilder builder = new PrefixAttributesBuilder();
610                 final List<RouteTag> routeTags = Lists.newArrayList();
611                 final List<ExtendedRouteTag> exRouteTags = Lists.newArrayList();
612                 for (final Entry<Integer, ByteList> entry : attributes.entrySet()) {
613                         logger.debug("Prefix attribute TLV {}", entry.getKey());
614                         for (final byte[] value : entry.getValue().getBytes()) {
615                                 switch (entry.getKey()) {
616                                 case 1152:
617                                         final boolean[] flags = ByteArray.parseBits(value[0]);
618                                         final boolean upDownBit = flags[2];
619                                         builder.setIgpBits(new IgpBitsBuilder().setUpDown(new UpDown(upDownBit)).build());
620                                         logger.trace("Parsed IGP flag (up/down bit) : {}", upDownBit);
621                                         break;
622                                 case 1153:
623                                         int offset = 0;
624                                         while (offset != value.length) {
625                                                 final RouteTag routeTag = new RouteTag(ByteArray.subByte(value, offset, 4));
626                                                 routeTags.add(routeTag);
627                                                 logger.trace("Parsed Route Tag: {}", routeTag);
628                                                 offset += 4;
629                                         }
630                                         break;
631                                 case 1154:
632                                         offset = 0;
633                                         while (offset != value.length) {
634                                                 final ExtendedRouteTag exRouteTag = new ExtendedRouteTag(value);
635                                                 exRouteTags.add(exRouteTag);
636                                                 logger.trace("Parsed Extended Route Tag: {}", exRouteTag);
637                                                 offset += 4;
638                                         }
639                                         break;
640                                 case 1155:
641                                         final IgpMetric metric = new IgpMetric(ByteArray.bytesToLong(value));
642                                         builder.setPrefixMetric(metric);
643                                         logger.trace("Parsed Metric: {}", metric);
644                                         break;
645                                 case 1156:
646                                         IpAddress fwdAddress = null;
647                                         switch (value.length) {
648                                         case 4:
649                                                 fwdAddress = new IpAddress(Ipv4Util.addressForBytes(value));
650                                                 break;
651                                         case 16:
652                                                 fwdAddress = new IpAddress(Ipv6Util.addressForBytes(value));
653                                                 break;
654                                         default:
655                                                 logger.debug("Ignoring unsupported forwarding address length {}", value.length);
656                                         }
657                                         logger.trace("Parsed FWD Address: {}", fwdAddress);
658                                         break;
659                                 case 1157:
660                                         final byte[] opaque = value;
661                                         logger.trace("Parsed Opaque value: {}", Arrays.toString(opaque));
662                                         break;
663                                 default:
664                                         throw new BGPParsingException("Prefix Attribute not recognized, type: " + entry.getKey());
665                                 }
666                         }
667                 }
668                 logger.debug("Finished parsing Prefix Attributes.");
669                 builder.setRouteTags(routeTags);
670                 builder.setExtendedTags(exRouteTags);
671                 return builder.build();
672         }
673 }