Initial framework migration to netty.
[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.util.Arrays;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Map.Entry;
15 import java.util.Set;
16 import java.util.SortedSet;
17
18 import org.opendaylight.protocol.bgp.concepts.BGPSubsequentAddressFamily;
19 import org.opendaylight.protocol.bgp.concepts.NextHop;
20 import org.opendaylight.protocol.bgp.linkstate.AdministrativeGroup;
21 import org.opendaylight.protocol.bgp.linkstate.AreaIdentifier;
22 import org.opendaylight.protocol.bgp.linkstate.DomainIdentifier;
23 import org.opendaylight.protocol.bgp.linkstate.ExtendedRouteTag;
24 import org.opendaylight.protocol.bgp.linkstate.IPv4InterfaceIdentifier;
25 import org.opendaylight.protocol.bgp.linkstate.IPv4PrefixIdentifier;
26 import org.opendaylight.protocol.bgp.linkstate.IPv4RouterIdentifier;
27 import org.opendaylight.protocol.bgp.linkstate.IPv6InterfaceIdentifier;
28 import org.opendaylight.protocol.bgp.linkstate.IPv6PrefixIdentifier;
29 import org.opendaylight.protocol.bgp.linkstate.IPv6RouterIdentifier;
30 import org.opendaylight.protocol.bgp.linkstate.ISISAreaIdentifier;
31 import org.opendaylight.protocol.bgp.linkstate.ISISLANIdentifier;
32 import org.opendaylight.protocol.bgp.linkstate.ISISNetworkPrefixState;
33 import org.opendaylight.protocol.bgp.linkstate.ISISRouterIdentifier;
34 import org.opendaylight.protocol.bgp.linkstate.InterfaceIdentifier;
35 import org.opendaylight.protocol.bgp.linkstate.LinkAnchor;
36 import org.opendaylight.protocol.bgp.linkstate.LinkIdentifier;
37 import org.opendaylight.protocol.bgp.linkstate.LinkProtectionType;
38 import org.opendaylight.protocol.bgp.linkstate.MPLSProtocol;
39 import org.opendaylight.protocol.bgp.linkstate.NetworkLinkImpl;
40 import org.opendaylight.protocol.bgp.linkstate.NetworkLinkState;
41 import org.opendaylight.protocol.bgp.linkstate.NetworkNodeImpl;
42 import org.opendaylight.protocol.bgp.linkstate.NetworkObjectState;
43 import org.opendaylight.protocol.bgp.linkstate.NetworkPrefixState;
44 import org.opendaylight.protocol.bgp.linkstate.NodeIdentifier;
45 import org.opendaylight.protocol.bgp.linkstate.OSPFInterfaceIdentifier;
46 import org.opendaylight.protocol.bgp.linkstate.OSPFNetworkPrefixState;
47 import org.opendaylight.protocol.bgp.linkstate.OSPFPrefixIdentifier;
48 import org.opendaylight.protocol.bgp.linkstate.OSPFRouteType;
49 import org.opendaylight.protocol.bgp.linkstate.OSPFRouterIdentifier;
50 import org.opendaylight.protocol.bgp.linkstate.OSPFv3LANIdentifier;
51 import org.opendaylight.protocol.bgp.linkstate.PrefixIdentifier;
52 import org.opendaylight.protocol.bgp.linkstate.RouteTag;
53 import org.opendaylight.protocol.bgp.linkstate.RouterIdentifier;
54 import org.opendaylight.protocol.bgp.linkstate.SourceProtocol;
55 import org.opendaylight.protocol.bgp.linkstate.TopologyIdentifier;
56 import org.opendaylight.protocol.bgp.linkstate.TopologyNodeInformation;
57 import org.opendaylight.protocol.bgp.linkstate.UnnumberedLinkIdentifier;
58 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
59 import org.opendaylight.protocol.bgp.parser.impl.BGPLinkMP;
60 import org.opendaylight.protocol.bgp.parser.impl.BGPNodeMP;
61 import org.opendaylight.protocol.bgp.parser.impl.ByteList;
62 import org.opendaylight.protocol.bgp.parser.impl.MPReach;
63 import org.opendaylight.protocol.concepts.ASNumber;
64 import org.opendaylight.protocol.concepts.Bandwidth;
65 import org.opendaylight.protocol.concepts.IGPMetric;
66 import org.opendaylight.protocol.concepts.IPv4Address;
67 import org.opendaylight.protocol.concepts.IPv4Prefix;
68 import org.opendaylight.protocol.concepts.IPv6;
69 import org.opendaylight.protocol.concepts.IPv6Address;
70 import org.opendaylight.protocol.concepts.IPv6Prefix;
71 import org.opendaylight.protocol.concepts.ISOSystemIdentifier;
72 import org.opendaylight.protocol.concepts.Metric;
73 import org.opendaylight.protocol.concepts.Prefix;
74 import org.opendaylight.protocol.concepts.SharedRiskLinkGroup;
75 import org.opendaylight.protocol.concepts.TEMetric;
76 import org.opendaylight.protocol.util.ByteArray;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
79
80 import com.google.common.base.Charsets;
81 import com.google.common.collect.Lists;
82 import com.google.common.collect.Maps;
83 import com.google.common.collect.Sets;
84 import com.google.common.primitives.UnsignedBytes;
85
86 /**
87  * Parser for Link State information.
88  * 
89  * @see <a href="http://tools.ietf.org/html/draft-gredler-idr-ls-distribution-01">BGP-LS draft</a>
90  */
91 public class LinkStateParser {
92
93         private static final Logger logger = LoggerFactory.getLogger(LinkStateParser.class);
94
95         private static final int TYPE_LENGTH = 2;
96
97         private static final int LENGTH_SIZE = 2;
98
99         private static final int ROUTE_DISTINGUISHER_LENGTH = 8;
100
101         private static final int PROTOCOL_ID_LENGTH = 1;
102
103         private static final int IDENTIFIER_LENGTH = 8;
104
105         private static final Set<Integer> nodeTlvs = Sets.newHashSet(263, 1024, 1025, 1026, 1027, 1028, 1029);
106
107         private static final Set<Integer> linkTlvs = Sets.newHashSet(1028, 1029, 1030, 1031, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095,
108                         1096, 1097, 1098);
109
110         private static final Set<Integer> prefixTlvs = Sets.newHashSet(1152, 1153, 1154, 1155, 1156, 1157);
111
112         private enum NlriType {
113                 LinkNLRI, NodeNLRI, IPv4Prefixes, IPv6Prefixes
114         }
115
116         private LinkStateParser() {
117         }
118
119         /**
120          * Parses common parts for Link State Nodes, Links and Prefixes, that includes protocol ID and identifier tlv.
121          * 
122          * @param reachable
123          * @param safi
124          * @param bytes
125          * @return BGPLinkMP or BGPNodeMP
126          * @throws BGPParsingException
127          */
128         protected static MPReach<?> parseLSNlri(final boolean reachable, final BGPSubsequentAddressFamily safi, final NextHop<?> nextHop,
129                         final byte[] bytes) throws BGPParsingException {
130                 if (bytes.length == 0)
131                         return null;
132                 int byteOffset = 0;
133                 final Set<LinkIdentifier> links = Sets.newHashSet();
134                 final Set<NodeIdentifier> nodes = Sets.newHashSet();
135                 final Set<PrefixIdentifier<?>> descs = Sets.newHashSet();
136
137                 long identifier = 0;
138                 SourceProtocol sp = null;
139
140                 while (byteOffset != bytes.length) {
141                         final NlriType type = parseNLRItype(ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH)));
142                         byteOffset += TYPE_LENGTH;
143                         // length means total length of the tlvs including route distinguisher not including the type field
144                         final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
145                         byteOffset += LENGTH_SIZE;
146                         if (safi == BGPSubsequentAddressFamily.MPLSLabeledVPN) {
147                                 // this parses route distinguisher
148                                 ByteArray.bytesToLong(ByteArray.subByte(bytes, byteOffset, ROUTE_DISTINGUISHER_LENGTH));
149                                 byteOffset += ROUTE_DISTINGUISHER_LENGTH;
150                         }
151                         // parse source protocol
152                         sp = parseProtocolId(ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, PROTOCOL_ID_LENGTH)));
153                         byteOffset += PROTOCOL_ID_LENGTH;
154
155                         // parse identifier
156                         identifier = ByteArray.bytesToLong(ByteArray.subByte(bytes, byteOffset, IDENTIFIER_LENGTH));
157                         byteOffset += IDENTIFIER_LENGTH;
158
159                         // if we are dealing with linkstate nodes/links, parse local node descriptor
160                         NodeIdentifier localDescriptor = null;
161                         int locallength = 0;
162                         final int localtype = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
163                         byteOffset += TYPE_LENGTH;
164                         locallength = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
165                         byteOffset += LENGTH_SIZE;
166                         if (localtype == 256) {
167                                 localDescriptor = parseNodeDescriptors(ByteArray.subByte(bytes, byteOffset, locallength));
168                         }
169                         byteOffset += locallength;
170                         final int restLength = length - ((safi == BGPSubsequentAddressFamily.MPLSLabeledVPN) ? ROUTE_DISTINGUISHER_LENGTH : 0)
171                                         - PROTOCOL_ID_LENGTH - IDENTIFIER_LENGTH - TYPE_LENGTH - LENGTH_SIZE - locallength;
172                         logger.debug("Restlength {}", restLength);
173                         switch (type) {
174                         case LinkNLRI:
175                                 links.add(parseLink(localDescriptor, sp, ByteArray.subByte(bytes, byteOffset, restLength)));
176                                 break;
177                         case IPv4Prefixes:
178                         case IPv6Prefixes:
179                                 descs.add(parsePrefixDescriptors(localDescriptor, ByteArray.subByte(bytes, byteOffset, restLength)));
180                                 break;
181                         case NodeNLRI:
182                                 // node nlri is already parsed as it contains only the common fields for node and link nlri
183                                 nodes.add(localDescriptor);
184                                 break;
185                         }
186                         byteOffset += restLength;
187                 }
188                 if (!links.isEmpty())
189                         return new BGPLinkMP(identifier, sp, reachable, links);
190                 else if (!nodes.isEmpty())
191                         return new BGPNodeMP(identifier, sp, reachable, nodes);
192                 // else if (!descs.isEmpty())
193                 // return new BGPIPv4PrefixMP(identifier, sp, descs, reachable);
194                 return null;
195         }
196
197         protected static Map<Integer, ByteList> parseLinkState(final byte[] bytes) {
198                 final Map<Integer, ByteList> map = new HashMap<Integer, ByteList>();
199                 int byteOffset = 0;
200                 while (byteOffset != bytes.length) {
201                         final int type = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
202                         byteOffset += TYPE_LENGTH;
203                         final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
204                         byteOffset += LENGTH_SIZE;
205                         final byte[] value = ByteArray.subByte(bytes, byteOffset, length);
206                         ByteList values = map.containsKey(type) ? values = map.get(type) : new ByteList();
207                         values.add(value);
208                         map.put(type, values);
209                         byteOffset += length;
210                 }
211                 return map;
212         }
213
214         public static boolean verifyLink(final Set<Integer> keys) {
215                 for (final Integer i : keys)
216                         if (!linkTlvs.contains(i)) {
217                                 logger.warn("Invalid link attribute {}", i);
218                                 return false;
219                         }
220                 return true;
221         }
222
223         public static boolean verifyNode(final Set<Integer> keys) {
224                 for (final Integer i : keys)
225                         if (!nodeTlvs.contains(i)) {
226                                 logger.warn("Invalid node attribute {}", i);
227                                 return false;
228                         }
229                 return true;
230         }
231
232         public static boolean verifyPrefix(final Set<Integer> keys) {
233                 for (final Integer i : keys)
234                         if (!prefixTlvs.contains(i)) {
235                                 logger.warn("Invalid prefix attribute {}", i);
236                                 return false;
237                         }
238                 return true;
239         }
240
241         /**
242          * Parse protocol ID from int to enum
243          * 
244          * @param protocolId int parsed from byte array
245          * @return enum SourceProtocol
246          * @throws BGPParsingException if the type is unrecognized
247          */
248         private static SourceProtocol parseProtocolId(final int protocolId) throws BGPParsingException {
249                 switch (protocolId) {
250                 case 0:
251                         return SourceProtocol.Unknown;
252                 case 1:
253                         return SourceProtocol.ISISLevel1;
254                 case 2:
255                         return SourceProtocol.ISISLevel2;
256                 case 3:
257                         return SourceProtocol.OSPF;
258                 case 4:
259                         return SourceProtocol.Direct;
260                 case 5:
261                         return SourceProtocol.Static;
262                 default:
263                         throw new BGPParsingException("Unknown Source Protocol ID: " + protocolId);
264                 }
265         }
266
267         private static OSPFRouteType parseRouteType(final int type) throws BGPParsingException {
268                 switch (type) {
269                 case 0:
270                         return null; // for IS-IS it needs to be 0
271                 case 1:
272                         return OSPFRouteType.Intra_Area;
273                 case 2:
274                         return OSPFRouteType.Inter_Area;
275                 case 3:
276                         return OSPFRouteType.External1;
277                 case 4:
278                         return OSPFRouteType.External2;
279                 case 5:
280                         return OSPFRouteType.NSSA1;
281                 case 6:
282                         return OSPFRouteType.NSSA2;
283                 default:
284                         throw new BGPParsingException("Unknown OSPF Route Type: " + type);
285                 }
286         }
287
288         private static LinkIdentifier parseLink(final NodeIdentifier local, final SourceProtocol spi, final byte[] bytes)
289                         throws BGPParsingException {
290                 int byteOffset = 0;
291                 final int type = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
292                 byteOffset += TYPE_LENGTH;
293                 final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
294                 byteOffset += LENGTH_SIZE;
295                 NodeIdentifier remote = null;
296                 if (type == 257) {
297                         remote = parseNodeDescriptors(ByteArray.subByte(bytes, byteOffset, length));
298                         byteOffset += length;
299                 }
300
301                 return parseLinkDescriptors(local, remote, ByteArray.subByte(bytes, byteOffset, bytes.length - byteOffset));
302         }
303
304         /**
305          * Parse Link Descriptors.
306          * 
307          * @param topology
308          * @param localAnchor
309          * @param remoteAnchor
310          * @param bytes
311          * @return
312          * @throws BGPParsingException
313          */
314         private static LinkIdentifier parseLinkDescriptors(final NodeIdentifier local, final NodeIdentifier remote, final byte[] bytes)
315                         throws BGPParsingException {
316                 int byteOffset = 0;
317                 final List<InterfaceIdentifier> localIdentifiers = Lists.newArrayList();
318                 final List<InterfaceIdentifier> remoteIdentifiers = Lists.newArrayList();
319                 TopologyIdentifier topId = null;
320                 while (byteOffset != bytes.length) {
321                         final int type = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
322                         byteOffset += TYPE_LENGTH;
323                         final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
324                         byteOffset += LENGTH_SIZE;
325                         final byte[] value = ByteArray.subByte(bytes, byteOffset, length);
326                         logger.debug("Parsing Link Descriptor: {}", Arrays.toString(value));
327                         switch (type) {
328                         case 258:
329                                 final UnnumberedLinkIdentifier l = new UnnumberedLinkIdentifier(ByteArray.bytesToLong(ByteArray.subByte(value, 0, 4)));
330                                 final UnnumberedLinkIdentifier r = new UnnumberedLinkIdentifier(ByteArray.bytesToLong(ByteArray.subByte(value, 4, 4)));
331                                 localIdentifiers.add(l);
332                                 remoteIdentifiers.add(r);
333                                 logger.trace("Parsed link local {} remote {} Identifiers.", local, remote);
334                                 break;
335                         case 259:
336                                 final IPv4InterfaceIdentifier lipv4 = new IPv4InterfaceIdentifier(new IPv4Address(value));
337                                 localIdentifiers.add(lipv4);
338                                 logger.trace("Parsed IPv4 interface address {}.", lipv4);
339                                 break;
340                         case 260:
341                                 final IPv4InterfaceIdentifier ripv4 = new IPv4InterfaceIdentifier(new IPv4Address(value));
342                                 remoteIdentifiers.add(ripv4);
343                                 logger.trace("Parsed IPv4 neighbor address {}.", ripv4);
344                                 break;
345                         case 261:
346                                 final IPv6InterfaceIdentifier lipv6 = new IPv6InterfaceIdentifier(new IPv6Address(value));
347                                 localIdentifiers.add(lipv6);
348                                 logger.trace("Parsed IPv6 interface address {}.", lipv6);
349                                 break;
350                         case 262:
351                                 final IPv6InterfaceIdentifier ripv6 = new IPv6InterfaceIdentifier(new IPv6Address(value));
352                                 remoteIdentifiers.add(ripv6);
353                                 logger.trace("Parsed IPv6 neighbor address {}.", ripv6);
354                                 break;
355                         case 263:
356                                 topId = new TopologyIdentifier(ByteArray.bytesToLong(value) & 0x3fff);
357                                 logger.trace("Parsed topology identifier {}.", topId);
358                                 break;
359                         default:
360                                 throw new BGPParsingException("Link Descriptor not recognized, type: " + type);
361                         }
362                         byteOffset += length;
363                 }
364                 logger.debug("Finished parsing Link descriptors.");
365                 if (localIdentifiers.size() != 1)
366                         throw new BGPParsingException("Invalid number of local interface identifiers.");
367                 final LinkAnchor localAnchor = new LinkAnchor(local, localIdentifiers.get(0));
368                 LinkAnchor remoteAnchor = null;
369                 if (remoteIdentifiers.size() > 0) {
370                         remoteAnchor = new LinkAnchor(remote, remoteIdentifiers.get(0));
371                 } else
372                         remoteAnchor = new LinkAnchor(remote, null);
373                 return new LinkIdentifier(topId, localAnchor, remoteAnchor);
374         }
375
376         /**
377          * Parse Node Descriptors. There can be only one TLV present from each type.
378          * 
379          * @param spi
380          * @param bytes
381          * @return
382          * @throws BGPParsingException
383          */
384         private static NodeIdentifier parseNodeDescriptors(final byte[] bytes) throws BGPParsingException {
385                 int byteOffset = 0;
386                 ASNumber asnumber = null;
387                 DomainIdentifier bgpId = null;
388                 AreaIdentifier ai = null;
389                 RouterIdentifier routerId = null;
390                 while (byteOffset != bytes.length) {
391                         final int type = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
392                         byteOffset += TYPE_LENGTH;
393                         final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
394                         byteOffset += LENGTH_SIZE;
395                         final byte[] value = ByteArray.subByte(bytes, byteOffset, length);
396                         logger.debug("Parsing Node Descriptor: {}", Arrays.toString(value));
397                         switch (type) {
398                         case 512:
399                                 asnumber = new ASNumber(ByteArray.bytesToLong(value));
400                                 logger.trace("Parsed AS number {}", asnumber);
401                                 break;
402                         case 513:
403                                 bgpId = new DomainIdentifier(value);
404                                 logger.trace("Parsed bgpId {}", bgpId);
405                                 break;
406                         case 514:
407                                 ai = new AreaIdentifier(value);
408                                 logger.trace("Parsed area identifier {}", ai);
409                                 break;
410                         case 515:
411                                 if (value.length == 6) {
412                                         routerId = new ISISRouterIdentifier(new ISOSystemIdentifier(ByteArray.subByte(value, 0, 6)));
413                                 } else if (value.length == 7) {
414                                         if (value[6] == 0) {
415                                                 logger.warn("PSN octet is 0. Ignoring System ID.");
416                                                 routerId = new ISISRouterIdentifier(new ISOSystemIdentifier(ByteArray.subByte(value, 0, 6)));
417                                                 break;
418                                         } else
419                                                 routerId = new ISISLANIdentifier(new ISOSystemIdentifier(ByteArray.subByte(value, 0, 6)), value[6]);
420                                 } else if (value.length == 4) {
421                                         routerId = new OSPFRouterIdentifier(ByteArray.subByte(value, 0, 4));
422                                 } else if (value.length == 8) {
423                                         final byte[] o = ByteArray.subByte(value, 0, 4); // FIXME: OSPFv3 vs OSPFv2
424                                         final OSPFInterfaceIdentifier a = new OSPFInterfaceIdentifier(ByteArray.subByte(value, 4, 4));
425                                         routerId = new OSPFv3LANIdentifier(new OSPFRouterIdentifier(o), a);
426                                 }
427                                 logger.trace("Parsed Router Identifier {}", routerId);
428                                 break;
429                         default:
430                                 throw new BGPParsingException("Node Descriptor not recognized, type: " + type);
431                         }
432                         byteOffset += length;
433                 }
434                 logger.debug("Finished parsing Node descriptors.");
435                 return new NodeIdentifier(asnumber, bgpId, ai, routerId);
436         }
437
438         private static PrefixIdentifier<?> parsePrefixDescriptors(final NodeIdentifier localDescriptor, final byte[] bytes)
439                         throws BGPParsingException {
440                 int byteOffset = 0;
441                 TopologyIdentifier topologyId = null;
442                 OSPFRouteType routeType = null;
443                 Prefix<?> prefix = null;
444                 while (byteOffset != bytes.length) {
445                         final int type = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
446                         byteOffset += TYPE_LENGTH;
447                         final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
448                         byteOffset += LENGTH_SIZE;
449                         final byte[] value = ByteArray.subByte(bytes, byteOffset, length);
450                         logger.trace("Parsing Prefix Descriptor: {}", Arrays.toString(value));
451                         switch (type) {
452                         case 263:
453                                 topologyId = new TopologyIdentifier(ByteArray.bytesToLong(value) & 0x3fff);
454                                 logger.trace("Parsed Topology Identifier: {}", topologyId);
455                                 break;
456                         case 264:
457                                 final int rt = ByteArray.bytesToInt(value);
458                                 routeType = parseRouteType(rt);
459                                 logger.trace("Parser RouteType: {}", routeType);
460                                 break;
461                         case 265:
462                                 final int prefixLength = UnsignedBytes.toInt(value[0]);
463                                 final int size = prefixLength / 8 + ((prefixLength % 8 == 0) ? 0 : 1);
464                                 if (size != value.length - 1) {
465                                         logger.debug("Expected length {}, actual length {}.", size, value.length - 1);
466                                         throw new BGPParsingException("Illegal length of IP reachability TLV: " + (value.length - 1));
467                                 }
468                                 prefix = IPv6.FAMILY.prefixForBytes(ByteArray.subByte(value, 1, size), prefixLength);
469                                 logger.trace("Parsed IP reachability info: {}", prefix);
470                                 break;
471                         default:
472                                 throw new BGPParsingException("Prefix Descriptor not recognized, type: " + type);
473                         }
474                         byteOffset += length;
475                 }
476                 logger.debug("Finished parsing Prefix descriptors.");
477                 if (routeType != null) {
478                         if (prefix instanceof IPv4Prefix) {
479                                 return new OSPFPrefixIdentifier<IPv4Address>(localDescriptor, (IPv4Prefix) prefix, routeType);
480                         } else {
481                                 return new OSPFPrefixIdentifier<IPv6Address>(localDescriptor, (IPv6Prefix) prefix, routeType);
482                         }
483                 }
484                 return (prefix instanceof IPv4Prefix) ? new IPv4PrefixIdentifier(localDescriptor, (IPv4Prefix) prefix)
485                                 : new IPv6PrefixIdentifier(localDescriptor, (IPv6Prefix) prefix);
486         }
487
488         /**
489          * Parse Link Attributes.
490          * 
491          * @param descriptors
492          * @param bytes
493          * @return
494          * @throws BGPParsingException
495          */
496         public static NetworkLinkImpl parseLinkAttributes(final LinkIdentifier linkId, final Map<Integer, ByteList> attributes)
497                         throws BGPParsingException {
498
499                 final Set<SharedRiskLinkGroup> sharedRiskLinkGroups = Sets.newHashSet();
500                 final Set<MPLSProtocol> enabledMPLSProtocols = Sets.newHashSet();
501                 NetworkLinkState state = NetworkLinkState.EMPTY;
502
503                 // FIXME: we should put these somewhere
504                 final Set<RouterIdentifier> localIds = Sets.newHashSet();
505                 final Set<RouterIdentifier> remoteIds = Sets.newHashSet();
506
507                 String name = null;
508                 for (final Entry<Integer, ByteList> entry : attributes.entrySet()) {
509                         logger.debug("Link attribute TLV {}", entry.getKey());
510
511                         for (final byte[] value : entry.getValue().getBytes()) {
512
513                                 switch (entry.getKey()) {
514                                 case 1028:
515                                         final IPv4RouterIdentifier lipv4 = new IPv4RouterIdentifier(new IPv4Address(value));
516                                         localIds.add(lipv4);
517                                         logger.trace("Parsed IPv4 Router-ID of local node: {}", lipv4);
518                                         break;
519                                 case 1029:
520                                         final IPv6RouterIdentifier lipv6 = new IPv6RouterIdentifier(new IPv6Address(value));
521                                         localIds.add(lipv6);
522                                         logger.trace("Parsed IPv6 Router-ID of local node: {}", lipv6);
523                                         break;
524                                 case 1030:
525                                         final IPv4RouterIdentifier ripv4 = new IPv4RouterIdentifier(new IPv4Address(value));
526                                         remoteIds.add(ripv4);
527                                         logger.trace("Parsed IPv4 Router-ID of remote node: {}", ripv4);
528                                         break;
529                                 case 1031:
530                                         final IPv6RouterIdentifier ripv6 = new IPv6RouterIdentifier(new IPv6Address(value));
531                                         remoteIds.add(ripv6);
532                                         logger.trace("Parsed IPv6 Router-ID of remote node: {}", ripv6);
533                                         break;
534                                 case 1088:
535                                         state = state.withAdministrativeGroup(new AdministrativeGroup(ByteArray.bytesToLong(value)));
536                                         logger.trace("Parsed Administrative Group {}", state.getAdministrativeGroup());
537                                         break;
538                                 case 1089:
539                                         state = state.withMaximumBandwidth(new Bandwidth(ByteArray.bytesToFloat(value)));
540                                         logger.trace("Parsed Max Bandwidth {}", state.getMaximumBandwidth());
541                                         break;
542                                 case 1090:
543                                         state = state.withReservableBandwidth(new Bandwidth(ByteArray.bytesToFloat(value)));
544                                         logger.trace("Parsed Max Reservable Bandwidth {}", state.getMaximumReservableBandwidth());
545                                         break;
546                                 case 1091:
547                                         int index = 0;
548                                         final Bandwidth[] unreservedBandwidth = new Bandwidth[8];
549                                         for (int i = 0; i < 8; i++) {
550                                                 unreservedBandwidth[i] = new Bandwidth(ByteArray.bytesToFloat(ByteArray.subByte(value, index, 4)));
551                                                 index += 4;
552                                         }
553                                         state = state.withUnreservedBandwidth(unreservedBandwidth);
554                                         logger.trace("Parsed Unreserved Bandwidth {}", Arrays.toString(state.getUnreservedBandwidth()));
555                                         break;
556                                 case 1092:
557                                         state = state.withMetric(TEMetric.class, new TEMetric(ByteArray.bytesToInt(value)));
558                                         logger.trace("Parsed Metric {}", state.getMetric(TEMetric.class));
559                                         break;
560                                 case 1093:
561                                         state = state.withProtectionType(parseLinkProtectionType(UnsignedBytes.toInt(value[0])));
562                                         logger.trace("Parsed Link Protection Type {}", state.getProtectionType());
563                                         break;
564                                 case 1094:
565                                         final boolean[] bits = ByteArray.parseBits(value[0]);
566                                         if (bits[0] == true) {
567                                                 enabledMPLSProtocols.add(MPLSProtocol.LDP);
568                                         }
569                                         if (bits[1] == true) {
570                                                 enabledMPLSProtocols.add(MPLSProtocol.RSVPTE);
571                                         }
572                                         logger.trace("Parsed MPLS Protocols: {}", Arrays.toString(enabledMPLSProtocols.toArray()));
573                                         break;
574                                 case 1095:
575                                         state = state.withDefaultMetric(new IGPMetric(ByteArray.bytesToLong(value)));
576                                         logger.trace("Parsed Metric {}", state.getDefaultMetric());
577                                         break;
578                                 case 1096:
579                                         int i = 0;
580                                         while (i != value.length) {
581                                                 sharedRiskLinkGroups.add(new SharedRiskLinkGroup(ByteArray.bytesToLong(ByteArray.subByte(value, i, 4))));
582                                                 i += 4;
583                                         }
584                                         logger.trace("Parsed Shared Risk Link Groups {}", Arrays.toString(sharedRiskLinkGroups.toArray()));
585                                         break;
586                                 case 1097:
587                                         final byte[] opaque = value;
588                                         logger.trace("Parsed Opaque value : {}", Arrays.toString(opaque));
589                                         break;
590                                 case 1098:
591                                         name = new String(value, Charsets.US_ASCII);
592                                         logger.trace("Parsed Link Name : ", name);
593                                         break;
594                                 default:
595                                         throw new BGPParsingException("Link Attribute not recognized, type: " + entry.getKey());
596                                 }
597                         }
598                 }
599                 state = state.withEnabledMPLSProtocols(enabledMPLSProtocols);
600                 state = state.withSharedRiskLinkGroups(sharedRiskLinkGroups);
601                 state = state.withSymbolicName(name);
602                 final NetworkLinkImpl link = new NetworkLinkImpl(linkId, state);
603                 logger.debug("Finished parsing Link Attributes.");
604                 return link;
605         }
606
607         /**
608          * Parse Node Attributes.
609          * 
610          * @param descriptors
611          * @param bytes
612          * @return
613          * @throws BGPParsingException
614          */
615         public static NetworkNodeImpl parseNodeAttributes(final NodeIdentifier nodeId, final Map<Integer, ByteList> attributes)
616                         throws BGPParsingException {
617                 final Map<TopologyIdentifier, TopologyNodeInformation> topologyMembership = Maps.newHashMap();
618                 final Set<ISISAreaIdentifier> areaMembership = Sets.newHashSet();
619                 final NetworkNodeImpl node = new NetworkNodeImpl(nodeId);
620                 final Set<RouterIdentifier> ids = Sets.newHashSet();
621                 for (final Entry<Integer, ByteList> entry : attributes.entrySet()) {
622                         logger.debug("Node attribute TLV {}", entry.getKey());
623                         for (final byte[] value : entry.getValue().getBytes()) {
624                                 switch (entry.getKey()) {
625                                 case 263:
626                                         final boolean[] bits = ByteArray.parseBits(value[0]);
627                                         final TopologyNodeInformation topNodeInfo = new TopologyNodeInformation(bits[1], bits[0]);
628                                         final TopologyIdentifier topId = new TopologyIdentifier(ByteArray.bytesToLong(value) & 0x3fff);
629                                         topologyMembership.put(topId, topNodeInfo);
630                                         logger.trace("Parsed Topology Identifier: {} and Topology Node Information: {}", topId, topNodeInfo);
631                                         break;
632                                 case 1024:
633                                         final boolean[] flags = ByteArray.parseBits(value[0]);
634                                         node.currentState().withExternal(flags[2]);
635                                         node.currentState().withAreaBorderRouter(flags[3]);
636                                         logger.trace("Parsed External bit {}, area border router {}.", flags[2], flags[3]);
637                                         break;
638                                 case 1025:
639                                         logger.debug("Ignoring opaque value: {}.", Arrays.toString(value));
640                                         break;
641                                 case 1026:
642                                         node.currentState().withDynamicHostname(new String(value, Charsets.US_ASCII));
643                                         logger.trace("Parsed Node Name {}", node.currentState().getDynamicHostname());
644                                         break;
645                                 case 1027:
646                                         final ISISAreaIdentifier ai = new ISISAreaIdentifier(value);
647                                         areaMembership.add(ai);
648                                         logger.trace("Parsed AreaIdentifier {}", ai);
649                                         break;
650                                 case 1028:
651                                         final IPv4RouterIdentifier ip4 = new IPv4RouterIdentifier(new IPv4Address(value));
652                                         ids.add(ip4);
653                                         logger.trace("Parsed IPv4 Router Identifier {}", ip4);
654                                         break;
655                                 case 1029:
656                                         final IPv6RouterIdentifier ip6 = new IPv6RouterIdentifier(new IPv6Address(value));
657                                         ids.add(ip6);
658                                         logger.trace("Parsed IPv6 Router Identifier {}", ip6);
659                                         break;
660                                 default:
661                                         throw new BGPParsingException("Node Attribute not recognized, type: " + entry.getKey());
662                                 }
663                         }
664                 }
665
666                 node.currentState().withAreaMembership(areaMembership);
667                 node.currentState().withIdentifierAlternatives(ids);
668                 node.currentState().withTopologyMembership(topologyMembership);
669                 logger.debug("Finished parsing Node Attributes.");
670                 return node;
671         }
672
673         public static NetworkPrefixState parsePrefixAttributes(final SourceProtocol src, final NetworkObjectState nos,
674                         final Map<Integer, ByteList> attributes) throws BGPParsingException {
675
676                 boolean upDownBit = false;
677                 final SortedSet<RouteTag> routeTags = Sets.newTreeSet();
678                 final SortedSet<ExtendedRouteTag> exRouteTags = Sets.newTreeSet();
679                 Metric<?> metric = null;
680                 IPv4Address fwdAddress4 = null;
681                 IPv6Address fwdAddress6 = null;
682                 for (final Entry<Integer, ByteList> entry : attributes.entrySet()) {
683                         logger.debug("Prefix attribute TLV {}", entry.getKey());
684                         for (final byte[] value : entry.getValue().getBytes()) {
685                                 switch (entry.getKey()) {
686                                 case 1152:
687                                         final boolean[] flags = ByteArray.parseBits(value[0]);
688                                         upDownBit = flags[2];
689                                         logger.trace("Parsed IGP flag (up/down bit) : {}", upDownBit);
690                                         break;
691                                 case 1153:
692                                         int offset = 0;
693                                         while (offset != value.length) {
694                                                 final RouteTag routeTag = new RouteTag(ByteArray.subByte(value, offset, 4));
695                                                 routeTags.add(routeTag);
696                                                 logger.trace("Parsed Route Tag: {}", routeTag);
697                                                 offset += 4;
698                                         }
699                                         break;
700                                 case 1154:
701                                         offset = 0;
702                                         while (offset != value.length) {
703                                                 final ExtendedRouteTag exRouteTag = new ExtendedRouteTag(value);
704                                                 exRouteTags.add(exRouteTag);
705                                                 logger.trace("Parsed Extended Route Tag: {}", exRouteTag);
706                                                 offset += 4;
707                                         }
708                                         break;
709                                 case 1155:
710                                         metric = new IGPMetric(ByteArray.bytesToLong(value));
711                                         logger.trace("Parsed Metric: {}", metric);
712                                         break;
713                                 case 1156:
714                                         switch (value.length) {
715                                         case 4:
716                                                 fwdAddress4 = new IPv4Address(value);
717                                                 logger.trace("Parsed FWD Address: {}", fwdAddress4);
718                                                 break;
719                                         case 16:
720                                                 fwdAddress6 = new IPv6Address(value);
721                                                 logger.trace("Parsed FWD Address: {}", fwdAddress6);
722                                                 break;
723                                         default:
724                                                 logger.debug("Ignoring unsupported forwarding address length {}", value.length);
725                                         }
726
727                                         break;
728                                 case 1157:
729                                         final byte[] opaque = value;
730                                         logger.trace("Parsed Opaque value: {}", Arrays.toString(opaque));
731                                         break;
732                                 default:
733                                         throw new BGPParsingException("Prefix Attribute not recognized, type: " + entry.getKey());
734                                 }
735                         }
736                 }
737
738                 logger.debug("Finished parsing Prefix Attributes.");
739
740                 final NetworkPrefixState nps = new NetworkPrefixState(nos, routeTags, metric);
741                 switch (src) {
742                 case ISISLevel1:
743                 case ISISLevel2:
744                         return new ISISNetworkPrefixState(nps, exRouteTags, upDownBit);
745                 case OSPF:
746                         if (fwdAddress4 != null)
747                                 return new OSPFNetworkPrefixState<IPv4Address>(nps, fwdAddress4);
748                         if (fwdAddress6 != null)
749                                 return new OSPFNetworkPrefixState<IPv6Address>(nps, fwdAddress6);
750                         logger.debug("OSPF-sourced has no forwarding address");
751                         return nps;
752                 default:
753                         return nps;
754                 }
755         }
756
757         /**
758          * Parse Link Protection Type from int to enum
759          * 
760          * @param type int parsed from byte array
761          * @return enum LinkProtectionType
762          * @throws BGPParsingException if the type is unrecognized
763          */
764         private static LinkProtectionType parseLinkProtectionType(final int type) throws BGPParsingException {
765                 switch (type) {
766                 case 1:
767                         return LinkProtectionType.EXTRA_TRAFFIC;
768                 case 2:
769                         return LinkProtectionType.UNPROTECTED;
770                 case 4:
771                         return LinkProtectionType.SHARED;
772                 case 8:
773                         return LinkProtectionType.DEDICATED_ONE_TO_ONE;
774                 case 16:
775                         return LinkProtectionType.DEDICATED_ONE_PLUS_ONE;
776                 default:
777                         throw new BGPParsingException("Link Protection Type not recognized: " + type);
778                 }
779         }
780
781         /**
782          * Parse NLRI Type from int to enum
783          * 
784          * @param type int parsed from byte array
785          * @return enum NlriType
786          * @throws BGPParsingException if the type is unrecognized
787          */
788         private static NlriType parseNLRItype(final int type) throws BGPParsingException {
789                 switch (type) {
790                 case 1:
791                         return NlriType.NodeNLRI;
792                 case 2:
793                         return NlriType.LinkNLRI;
794                 case 3:
795                         return NlriType.IPv4Prefixes;
796                 case 4:
797                         return NlriType.IPv6Prefixes;
798                 default:
799                         throw new BGPParsingException("NLRI Type not recognized: " + type);
800                 }
801         }
802 }