Bug-731: Fixed few major Sonar warnings
[bgpcep.git] / bgp / linkstate / src / main / java / org / opendaylight / protocol / bgp / linkstate / LinkstateAttributeParser.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.linkstate;
9
10 import com.google.common.base.Charsets;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.HashMultimap;
13 import com.google.common.collect.Lists;
14 import com.google.common.collect.Multimap;
15 import com.google.common.net.InetAddresses;
16 import io.netty.buffer.ByteBuf;
17 import io.netty.buffer.ByteBufUtil;
18 import io.netty.buffer.Unpooled;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.BitSet;
22 import java.util.List;
23 import java.util.Map.Entry;
24 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
25 import org.opendaylight.protocol.bgp.parser.spi.AttributeParser;
26 import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer;
27 import org.opendaylight.protocol.bgp.parser.spi.AttributeUtil;
28 import org.opendaylight.protocol.util.ByteArray;
29 import org.opendaylight.protocol.util.Ipv4Util;
30 import org.opendaylight.protocol.util.Ipv6Util;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.AdministrativeGroup;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.ExtendedRouteTag;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.IgpBits.UpDown;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.Ipv4RouterIdentifier;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.Ipv6RouterIdentifier;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.IsisAreaIdentifier;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.LinkProtectionType;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.MplsProtocolMask;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.NlriType;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.NodeFlagBits;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.PathAttributes1;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.PathAttributes1Builder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.RouteTag;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.TopologyIdentifier;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.link.state.UnreservedBandwidth;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.link.state.UnreservedBandwidthBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.linkstate.destination.CLinkstateDestination;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.prefix.state.IgpBitsBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.LinkstatePathAttribute;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.LinkstatePathAttributeBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.linkstate.path.attribute.LinkStateAttribute;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.linkstate.path.attribute.link.state.attribute.LinkAttributesCase;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.linkstate.path.attribute.link.state.attribute.LinkAttributesCaseBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.linkstate.path.attribute.link.state.attribute.NodeAttributesCase;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.linkstate.path.attribute.link.state.attribute.NodeAttributesCaseBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.linkstate.path.attribute.link.state.attribute.PrefixAttributesCase;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.linkstate.path.attribute.link.state.attribute.PrefixAttributesCaseBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.linkstate.path.attribute.link.state.attribute.link.attributes._case.LinkAttributes;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.linkstate.path.attribute.link.state.attribute.link.attributes._case.LinkAttributesBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.linkstate.path.attribute.link.state.attribute.node.attributes._case.NodeAttributes;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.linkstate.path.attribute.link.state.attribute.node.attributes._case.NodeAttributesBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.linkstate.path.attribute.link.state.attribute.prefix.attributes._case.PrefixAttributes;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.linkstate.path.attribute.link.state.attribute.prefix.attributes._case.PrefixAttributesBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLinkstateCase;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributes;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributesBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes2;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.destination.DestinationType;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.Bandwidth;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.IgpMetric;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.Metric;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.TeMetric;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev130820.SrlgId;
75 import org.opendaylight.yangtools.yang.binding.DataObject;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
78
79 /**
80  * Parser for Link State Path Attribute.
81  *
82  * @see <a href="http://tools.ietf.org/html/draft-gredler-idr-ls-distribution-04">BGP-LS draft</a>
83  */
84 public class LinkstateAttributeParser implements AttributeParser, AttributeSerializer {
85
86     private static final int TYPE = 29;
87
88     private static final int LEGACY_TYPE = 99;
89
90     private static final Logger LOG = LoggerFactory.getLogger(LinkstateAttributeParser.class);
91
92     private static final int ROUTE_TAG_LENGTH = 4;
93
94     private static final int EXTENDED_ROUTE_TAG_LENGTH = 8;
95
96     private static final int UNRESERVED_BW_COUNT = 8;
97
98     private static final int BANDWIDTH_LENGTH = 4;
99
100     // node flag bits
101     private static final int OVERLOAD_BIT = 7;
102     private static final int ATTACHED_BIT = 6;
103     private static final int EXTERNAL_BIT = 5;
104     private static final int ABBR_BIT = 4;
105
106     // MPLS protection mask bits
107     private static final int LDP_BIT = 7;
108     private static final int RSVP_BIT = 6;
109
110     private static final int UP_DOWN_BIT = 7;
111
112     private final int type;
113
114     public LinkstateAttributeParser(final boolean isIanaAssignedType) {
115         if(isIanaAssignedType) {
116             this.type = TYPE;
117         } else {
118             this.type = LEGACY_TYPE;
119         }
120     }
121
122     public int getType() {
123         return type;
124     }
125
126     private NlriType getNlriType(final PathAttributesBuilder pab) {
127         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes1 mpr = pab.getAugmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes1.class);
128         if (mpr != null && mpr.getMpReachNlri() != null) {
129             final DestinationType dt = mpr.getMpReachNlri().getAdvertizedRoutes().getDestinationType();
130             if (dt instanceof DestinationLinkstateCase) {
131                 for (final CLinkstateDestination d : ((DestinationLinkstateCase) dt).getDestinationLinkstate().getCLinkstateDestination()) {
132                     return d.getNlriType();
133                 }
134             }
135         } else {
136             LOG.debug("No MP_REACH attribute present");
137         }
138         final PathAttributes2 mpu = pab.getAugmentation(PathAttributes2.class);
139         if (mpu != null && mpu.getMpUnreachNlri() != null) {
140             final DestinationType dt = mpu.getMpUnreachNlri().getWithdrawnRoutes().getDestinationType();
141             if (dt instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationLinkstateCase) {
142                 for (final CLinkstateDestination d : ((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationLinkstateCase) dt).getDestinationLinkstate().getCLinkstateDestination()) {
143                     return d.getNlriType();
144                 }
145             }
146         } else {
147             LOG.debug("No MP_UNREACH attribute present");
148         }
149         return null;
150     }
151
152     @Override
153     public void parseAttribute(final ByteBuf buffer, final PathAttributesBuilder builder) throws BGPParsingException {
154         final NlriType nlriType = getNlriType(builder);
155         if (nlriType == null) {
156             LOG.warn("No Linkstate NLRI found, not parsing Linkstate attribute");
157             return;
158         }
159         final PathAttributes1 a = new PathAttributes1Builder().setLinkstatePathAttribute(parseLinkState(nlriType, buffer)).build();
160         builder.addAugmentation(PathAttributes1.class, a);
161     }
162
163     private static LinkstatePathAttribute parseLinkState(final NlriType nlri, final ByteBuf buffer) throws BGPParsingException {
164         /*
165          * e.g. IS-IS Area Identifier TLV can occur multiple times
166          */
167         final Multimap<Integer, ByteBuf> map = HashMultimap.create();
168         while (buffer.isReadable()) {
169             final int type = buffer.readUnsignedShort();
170             final int length = buffer.readUnsignedShort();
171             final ByteBuf value = buffer.slice(buffer.readerIndex(), length);
172             map.put(type, value);
173             buffer.skipBytes(length);
174         }
175         final LinkstatePathAttributeBuilder builder = new LinkstatePathAttributeBuilder();
176
177         switch (nlri) {
178         case Ipv4Prefix:
179         case Ipv6Prefix:
180             builder.setLinkStateAttribute(parsePrefixAttributes(map));
181             return builder.build();
182         case Link:
183             builder.setLinkStateAttribute(parseLinkAttributes(map));
184             return builder.build();
185         case Node:
186             builder.setLinkStateAttribute(parseNodeAttributes(map));
187             return builder.build();
188         }
189         throw new IllegalStateException("Unhandled NLRI type " + nlri);
190     }
191
192     /**
193      * Parse Link Attributes.
194      *
195      * @param attributes key is the tlv type and value is the value of the tlv
196      * @return {@link LinkStateAttribute}
197      */
198     private static LinkStateAttribute parseLinkAttributes(final Multimap<Integer, ByteBuf> attributes) {
199         final LinkAttributesBuilder builder = new LinkAttributesBuilder();
200         for (final Entry<Integer, ByteBuf> entry : attributes.entries()) {
201             LOG.trace("Link attribute TLV {}", entry.getKey());
202             final int key = entry.getKey();
203             final ByteBuf value = entry.getValue();
204             switch (key) {
205             case TlvCode.LOCAL_IPV4_ROUTER_ID:
206                 final Ipv4RouterIdentifier lipv4 = new Ipv4RouterIdentifier(Ipv4Util.addressForByteBuf(value));
207                 builder.setLocalIpv4RouterId(lipv4);
208                 LOG.debug("Parsed IPv4 Router-ID of local node: {}", lipv4);
209                 break;
210             case TlvCode.LOCAL_IPV6_ROUTER_ID:
211                 final Ipv6RouterIdentifier lipv6 = new Ipv6RouterIdentifier(Ipv6Util.addressForByteBuf(value));
212                 builder.setLocalIpv6RouterId(lipv6);
213                 LOG.debug("Parsed IPv6 Router-ID of local node: {}", lipv6);
214                 break;
215             case TlvCode.REMOTE_IPV4_ROUTER_ID:
216                 final Ipv4RouterIdentifier ripv4 = new Ipv4RouterIdentifier(Ipv4Util.addressForByteBuf(value));
217                 builder.setRemoteIpv4RouterId(ripv4);
218                 LOG.debug("Parsed IPv4 Router-ID of remote node: {}", ripv4);
219                 break;
220             case TlvCode.REMOTE_IPV6_ROUTER_ID:
221                 final Ipv6RouterIdentifier ripv6 = new Ipv6RouterIdentifier(Ipv6Util.addressForByteBuf(value));
222                 builder.setRemoteIpv6RouterId(ripv6);
223                 LOG.debug("Parsed IPv6 Router-ID of remote node: {}", ripv6);
224                 break;
225             case TlvCode.ADMIN_GROUP:
226                 builder.setAdminGroup(new AdministrativeGroup(value.readUnsignedInt()));
227                 LOG.debug("Parsed Administrative Group {}", builder.getAdminGroup());
228                 break;
229             case TlvCode.MAX_BANDWIDTH:
230                 builder.setMaxLinkBandwidth(new Bandwidth(ByteArray.readAllBytes(value)));
231                 LOG.debug("Parsed Max Bandwidth {}", builder.getMaxLinkBandwidth());
232                 break;
233             case TlvCode.MAX_RESERVABLE_BANDWIDTH:
234                 builder.setMaxReservableBandwidth(new Bandwidth(ByteArray.readAllBytes(value)));
235                 LOG.debug("Parsed Max Reservable Bandwidth {}", builder.getMaxReservableBandwidth());
236                 break;
237             case TlvCode.UNRESERVED_BANDWIDTH:
238                 final List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.link.state.UnreservedBandwidth> unreservedBandwidth = new ArrayList<>(UNRESERVED_BW_COUNT);
239                 for (int i = 0; i < UNRESERVED_BW_COUNT; i++) {
240                     final ByteBuf v = value.slice(value.readerIndex(), BANDWIDTH_LENGTH);
241                     unreservedBandwidth.add(new UnreservedBandwidthBuilder().setBandwidth(new Bandwidth(ByteArray.readAllBytes(v))).setPriority((short) i).build());
242                     value.skipBytes(BANDWIDTH_LENGTH);
243                 }
244                 builder.setUnreservedBandwidth(unreservedBandwidth);
245                 LOG.debug("Parsed Unreserved Bandwidth {}", builder.getUnreservedBandwidth());
246                 break;
247             case TlvCode.TE_METRIC:
248                 builder.setTeMetric(new TeMetric(ByteArray.bytesToLong(ByteArray.readAllBytes(value))));
249                 LOG.debug("Parsed Metric {}", builder.getTeMetric());
250                 break;
251             case TlvCode.LINK_PROTECTION_TYPE:
252                 final int l = value.readShort();
253                 final LinkProtectionType lpt = LinkProtectionType.forValue(l);
254                 if (lpt == null) {
255                     LOG.warn("Link Protection Type not recognized: {}", l);
256                     break;
257                 }
258                 builder.setLinkProtection(lpt);
259                 LOG.debug("Parsed Link Protection Type {}", lpt);
260                 break;
261             case TlvCode.MPLS_PROTOCOL:
262                 final BitSet bits = BitSet.valueOf(ByteArray.readAllBytes(value));
263                 builder.setMplsProtocol(new MplsProtocolMask(bits.get(LDP_BIT), bits.get(RSVP_BIT)));
264                 LOG.debug("Parsed MPLS Protocols: {}", builder.getMplsProtocol());
265                 break;
266             case TlvCode.METRIC:
267                 // length can 3, 2 or 1
268                 builder.setMetric(new Metric(ByteArray.bytesToLong(ByteArray.readAllBytes(value))));
269                 LOG.debug("Parsed Metric {}", builder.getMetric());
270                 break;
271             case TlvCode.SHARED_RISK_LINK_GROUP:
272                 final List<SrlgId> sharedRiskLinkGroups = new ArrayList<>();
273                 while (value.isReadable()) {
274                     sharedRiskLinkGroups.add(new SrlgId(value.readUnsignedInt()));
275                 }
276                 builder.setSharedRiskLinkGroups(sharedRiskLinkGroups);
277                 LOG.debug("Parsed Shared Risk Link Groups {}", Arrays.toString(sharedRiskLinkGroups.toArray()));
278                 break;
279             case TlvCode.LINK_OPAQUE:
280                 LOG.debug("Parsed Opaque value : {}", ByteBufUtil.hexDump(value));
281                 break;
282             case TlvCode.LINK_NAME:
283                 final String name = new String(ByteArray.readAllBytes(value), Charsets.US_ASCII);
284                 builder.setLinkName(name);
285                 LOG.debug("Parsed Link Name : {}", name);
286                 break;
287             default:
288                 LOG.warn("TLV {} is not a valid link attribute, ignoring it", key);
289             }
290         }
291         LOG.trace("Finished parsing Link Attributes.");
292         return new LinkAttributesCaseBuilder().setLinkAttributes(builder.build()).build();
293     }
294
295     /**
296      * Parse Node Attributes.
297      *
298      * @param attributes key is the tlv type and value is the value of the tlv
299      * @return {@link LinkStateAttribute}
300      */
301     private static LinkStateAttribute parseNodeAttributes(final Multimap<Integer, ByteBuf> attributes) {
302         final List<TopologyIdentifier> topologyMembership = Lists.newArrayList();
303         final List<IsisAreaIdentifier> areaMembership = Lists.newArrayList();
304         final NodeAttributesBuilder builder = new NodeAttributesBuilder();
305         for (final Entry<Integer, ByteBuf> entry : attributes.entries()) {
306             final int key = entry.getKey();
307             final ByteBuf value = entry.getValue();
308             LOG.trace("Node attribute TLV {}", key);
309             switch (key) {
310             case TlvCode.MULTI_TOPOLOGY_ID:
311                 while (value.isReadable()) {
312                     final TopologyIdentifier topId = new TopologyIdentifier(value.readUnsignedShort() & LinkstateNlriParser.TOPOLOGY_ID_OFFSET);
313                     topologyMembership.add(topId);
314                     LOG.debug("Parsed Topology Identifier: {}", topId);
315                 }
316                 break;
317             case TlvCode.NODE_FLAG_BITS:
318                 final BitSet flags = BitSet.valueOf(ByteArray.readAllBytes(value));
319                 builder.setNodeFlags(new NodeFlagBits(flags.get(OVERLOAD_BIT), flags.get(ATTACHED_BIT), flags.get(EXTERNAL_BIT), flags.get(ABBR_BIT)));
320                 LOG.debug("Parsed Overload bit: {}, attached bit: {}, external bit: {}, area border router: {}.",
321                     flags.get(OVERLOAD_BIT), flags.get(ATTACHED_BIT), flags.get(EXTERNAL_BIT), flags.get(ABBR_BIT));
322                 break;
323             case TlvCode.NODE_OPAQUE:
324                 LOG.debug("Ignoring opaque value: {}.", ByteBufUtil.hexDump(value));
325                 break;
326             case TlvCode.DYNAMIC_HOSTNAME:
327                 builder.setDynamicHostname(new String(ByteArray.readAllBytes(value), Charsets.US_ASCII));
328                 LOG.debug("Parsed Node Name {}", builder.getDynamicHostname());
329                 break;
330             case TlvCode.ISIS_AREA_IDENTIFIER:
331                 final IsisAreaIdentifier ai = new IsisAreaIdentifier(ByteArray.readAllBytes(value));
332                 areaMembership.add(ai);
333                 LOG.debug("Parsed AreaIdentifier {}", ai);
334                 break;
335             case TlvCode.LOCAL_IPV4_ROUTER_ID:
336                 final Ipv4RouterIdentifier ip4 = new Ipv4RouterIdentifier(Ipv4Util.addressForByteBuf(value));
337                 builder.setIpv4RouterId(ip4);
338                 LOG.debug("Parsed IPv4 Router Identifier {}", ip4);
339                 break;
340             case TlvCode.LOCAL_IPV6_ROUTER_ID:
341                 final Ipv6RouterIdentifier ip6 = new Ipv6RouterIdentifier(Ipv6Util.addressForByteBuf(value));
342                 builder.setIpv6RouterId(ip6);
343                 LOG.debug("Parsed IPv6 Router Identifier {}", ip6);
344                 break;
345             default:
346                 LOG.warn("TLV {} is not a valid node attribute, ignoring it", key);
347             }
348         }
349         LOG.trace("Finished parsing Node Attributes.");
350         builder.setTopologyIdentifier(topologyMembership);
351         builder.setIsisAreaId(areaMembership);
352         return new NodeAttributesCaseBuilder().setNodeAttributes(builder.build()).build();
353     }
354
355     /**
356      * Parse prefix attributes.
357      *
358      * @param attributes key is the tlv type and value are the value bytes of the tlv
359      * @return {@link LinkStateAttribute}
360      */
361     private static LinkStateAttribute parsePrefixAttributes(final Multimap<Integer, ByteBuf> attributes) {
362         final PrefixAttributesBuilder builder = new PrefixAttributesBuilder();
363         final List<RouteTag> routeTags = Lists.newArrayList();
364         final List<ExtendedRouteTag> exRouteTags = Lists.newArrayList();
365         for (final Entry<Integer, ByteBuf> entry : attributes.entries()) {
366             final int key = entry.getKey();
367             final ByteBuf value = entry.getValue();
368             LOG.trace("Prefix attribute TLV {}", key);
369             switch (key) {
370             case TlvCode.IGP_FLAGS:
371                 final BitSet flags = BitSet.valueOf(ByteArray.readAllBytes(value));
372                 final boolean upDownBit = flags.get(UP_DOWN_BIT);
373                 builder.setIgpBits(new IgpBitsBuilder().setUpDown(new UpDown(upDownBit)).build());
374                 LOG.debug("Parsed IGP flag (up/down bit) : {}", upDownBit);
375                 break;
376             case TlvCode.ROUTE_TAG:
377                 while (value.isReadable()) {
378                     final RouteTag routeTag = new RouteTag(ByteArray.readBytes(value, ROUTE_TAG_LENGTH));
379                     routeTags.add(routeTag);
380                     LOG.debug("Parsed Route Tag: {}", routeTag);
381                 }
382                 break;
383             case TlvCode.EXTENDED_ROUTE_TAG:
384                 while (value.isReadable()) {
385                     final ExtendedRouteTag exRouteTag = new ExtendedRouteTag(ByteArray.readBytes(value, EXTENDED_ROUTE_TAG_LENGTH));
386                     exRouteTags.add(exRouteTag);
387                     LOG.debug("Parsed Extended Route Tag: {}", exRouteTag);
388                 }
389                 break;
390             case TlvCode.PREFIX_METRIC:
391                 final IgpMetric metric = new IgpMetric(value.readUnsignedInt());
392                 builder.setPrefixMetric(metric);
393                 LOG.debug("Parsed Metric: {}", metric);
394                 break;
395             case TlvCode.FORWARDING_ADDRESS:
396                 final IpAddress fwdAddress = parseForwardingAddress(value);
397                 builder.setOspfForwardingAddress(fwdAddress);
398                 LOG.debug("Parsed FWD Address: {}", fwdAddress);
399                 break;
400             case TlvCode.PREFIX_OPAQUE:
401                 LOG.debug("Parsed Opaque value: {}, not preserving it", ByteBufUtil.hexDump(value));
402                 break;
403             default:
404                 LOG.warn("TLV {} is not a valid prefix attribute, ignoring it", key);
405             }
406         }
407         LOG.trace("Finished parsing Prefix Attributes.");
408         builder.setRouteTags(routeTags);
409         builder.setExtendedTags(exRouteTags);
410         return new PrefixAttributesCaseBuilder().setPrefixAttributes(builder.build()).build();
411     }
412
413     private static IpAddress parseForwardingAddress(final ByteBuf value) {
414         IpAddress fwdAddress = null;
415         switch (value.readableBytes()) {
416         case Ipv4Util.IP4_LENGTH:
417             fwdAddress = new IpAddress(Ipv4Util.addressForByteBuf(value));
418             break;
419         case Ipv6Util.IPV6_LENGTH:
420             fwdAddress = new IpAddress(Ipv6Util.addressForByteBuf(value));
421             break;
422         default:
423             LOG.debug("Ignoring unsupported forwarding address length {}", value.readableBytes());
424         }
425         return fwdAddress;
426     }
427
428     /**
429      * Serialize linkstate attributes.
430      *
431      * @param attribute DataObject representing LinkstatePathAttribute
432      * @param byteAggregator ByteBuf where all serialized data are aggregated
433      */
434
435     @Override
436     public void serializeAttribute(final DataObject attribute, final ByteBuf byteAggregator) {
437         Preconditions.checkArgument(attribute instanceof PathAttributes, "Attribute parameter is not a PathAttribute object.");
438         final PathAttributes1 pathAttributes1 = ((PathAttributes) attribute).getAugmentation(PathAttributes1.class);
439         if (pathAttributes1 == null) {
440             return;
441         }
442         final LinkStateAttribute linkState = pathAttributes1.getLinkstatePathAttribute().getLinkStateAttribute();
443         final ByteBuf lsBuffer = Unpooled.buffer();
444         if (linkState instanceof LinkAttributesCase) {
445             serializeLinkAttributes((LinkAttributesCase) linkState, lsBuffer);
446         } else if (linkState instanceof NodeAttributesCase) {
447             serializeNodeAttributes((NodeAttributesCase) linkState, lsBuffer);
448         } else if (linkState instanceof PrefixAttributesCase) {
449             serializePrefixAttributes((PrefixAttributesCase) linkState, lsBuffer);
450         }
451         AttributeUtil.formatAttribute(AttributeUtil.OPTIONAL, getType(), lsBuffer, byteAggregator);
452     }
453
454     private void serializeLinkAttributes(final LinkAttributesCase linkAttributesCase, final ByteBuf byteAggregator) {
455         final LinkAttributes linkAttributes = linkAttributesCase.getLinkAttributes();
456         LOG.trace("Started serializing Link Attributes");
457         if (linkAttributes.getLocalIpv4RouterId() != null) {
458             writeTLV(TlvCode.LOCAL_IPV4_ROUTER_ID, Unpooled.wrappedBuffer(InetAddresses.forString(linkAttributes.getLocalIpv4RouterId().getValue()).getAddress()), byteAggregator);
459         }
460         if (linkAttributes.getLocalIpv6RouterId() != null) {
461             writeTLV(TlvCode.LOCAL_IPV6_ROUTER_ID, Unpooled.wrappedBuffer(InetAddresses.forString(linkAttributes.getLocalIpv6RouterId().getValue()).getAddress()), byteAggregator);
462         }
463         if (linkAttributes.getRemoteIpv4RouterId() != null) {
464             writeTLV(TlvCode.REMOTE_IPV4_ROUTER_ID, Unpooled.wrappedBuffer(InetAddresses.forString(linkAttributes.getRemoteIpv4RouterId().getValue()).getAddress()), byteAggregator);
465         }
466         if (linkAttributes.getRemoteIpv6RouterId() != null) {
467             writeTLV(TlvCode.REMOTE_IPV6_ROUTER_ID, Unpooled.wrappedBuffer(InetAddresses.forString(linkAttributes.getRemoteIpv6RouterId().getValue()).getAddress()), byteAggregator);
468         }
469         if (linkAttributes.getAdminGroup() != null) {
470             writeTLV(TlvCode.ADMIN_GROUP, Unpooled.copyInt(linkAttributes.getAdminGroup().getValue().intValue()), byteAggregator);
471         }
472         if (linkAttributes.getMaxLinkBandwidth() != null) {
473             writeTLV(TlvCode.MAX_BANDWIDTH, Unpooled.wrappedBuffer(linkAttributes.getMaxLinkBandwidth().getValue()), byteAggregator);
474         }
475         if (linkAttributes.getMaxReservableBandwidth() != null) {
476             writeTLV(TlvCode.MAX_RESERVABLE_BANDWIDTH, Unpooled.wrappedBuffer(linkAttributes.getMaxReservableBandwidth().getValue()), byteAggregator);
477         }
478         // this sub-TLV contains eight 32-bit IEEE floating point numbers
479         final List<UnreservedBandwidth> ubList = linkAttributes.getUnreservedBandwidth();
480         if (ubList != null && !ubList.isEmpty()) {
481             final ByteBuf unreservedBandwithBuf = Unpooled.buffer();
482             for (final UnreservedBandwidth unreservedBandwidth : ubList) {
483                 unreservedBandwithBuf.writeBytes(unreservedBandwidth.getBandwidth().getValue());
484             }
485             writeTLV(TlvCode.UNRESERVED_BANDWIDTH, unreservedBandwithBuf, byteAggregator);
486         }
487         if (linkAttributes.getTeMetric() != null) {
488             writeTLV(TlvCode.TE_METRIC, Unpooled.copyLong(linkAttributes.getTeMetric().getValue().longValue()), byteAggregator);
489         }
490         if (linkAttributes.getLinkProtection() != null) {
491             writeTLV(TlvCode.LINK_PROTECTION_TYPE, Unpooled.copyShort(linkAttributes.getLinkProtection().getIntValue()), byteAggregator);
492         }
493         serializeMplsProtocolMask(linkAttributes.getMplsProtocol(), byteAggregator);
494         if (linkAttributes.getMetric() != null) {
495             // size of metric can be 1,2 or 3 depending on the protocol
496             writeTLV(TlvCode.METRIC, Unpooled.copyMedium(linkAttributes.getMetric().getValue().intValue()), byteAggregator);
497         }
498         final List<SrlgId> srlgList = linkAttributes.getSharedRiskLinkGroups();
499         if (srlgList != null && !srlgList.isEmpty()) {
500             final ByteBuf sharedRLGBuf = Unpooled.buffer();
501             for (final SrlgId srlgId : srlgList) {
502                 sharedRLGBuf.writeInt(srlgId.getValue().intValue());
503             }
504             writeTLV(TlvCode.SHARED_RISK_LINK_GROUP, sharedRLGBuf, byteAggregator);
505         }
506         if (linkAttributes.getLinkName() != null) {
507             writeTLV(TlvCode.LINK_NAME, Unpooled.wrappedBuffer(Charsets.UTF_8.encode(linkAttributes.getLinkName())), byteAggregator);
508         }
509         LOG.trace("Finished serializing Link Attributes");
510     }
511
512     private static void serializeMplsProtocolMask(final MplsProtocolMask mplsProtocolMask, final ByteBuf byteAggregator ) {
513         if (mplsProtocolMask != null) {
514             final ByteBuf mplsProtocolMaskBuf = Unpooled.buffer();
515             final BitSet mask = new BitSet();
516             if (mplsProtocolMask.isLdp() != null) {
517                 mask.set(LDP_BIT, mplsProtocolMask.isLdp());
518             }
519             if (mplsProtocolMask.isRsvpte() != null) {
520                 mask.set(RSVP_BIT, mplsProtocolMask.isRsvpte());
521             }
522             mplsProtocolMaskBuf.writeBytes(mask.toByteArray());
523             writeTLV(TlvCode.MPLS_PROTOCOL, mplsProtocolMaskBuf, byteAggregator);
524         }
525     }
526
527     private void serializeNodeAttributes(final NodeAttributesCase nodeAttributesCase, final ByteBuf byteAggregator) {
528         LOG.trace("Started serializing Node Attributes");
529         final NodeAttributes nodeAttributes = nodeAttributesCase.getNodeAttributes();
530         final List<TopologyIdentifier> topList = nodeAttributes.getTopologyIdentifier();
531         if (topList != null && !topList.isEmpty()) {
532             final ByteBuf mpIdBuf = Unpooled.buffer();
533             for (final TopologyIdentifier topologyIdentifier : topList) {
534                 mpIdBuf.writeShort(topologyIdentifier.getValue());
535             }
536             writeTLV(TlvCode.MULTI_TOPOLOGY_ID, mpIdBuf, byteAggregator);
537         }
538         serializeNodeFlagBits(nodeAttributes.getNodeFlags(), byteAggregator);
539         if (nodeAttributes.getDynamicHostname() != null) {
540             writeTLV(TlvCode.DYNAMIC_HOSTNAME, Unpooled.wrappedBuffer(Charsets.UTF_8.encode(nodeAttributes.getDynamicHostname())), byteAggregator);
541         }
542         final List<IsisAreaIdentifier> isisList = nodeAttributes.getIsisAreaId();
543         if (isisList != null && !isisList.isEmpty()) {
544             for (final IsisAreaIdentifier isisAreaIdentifier : isisList) {
545                 writeTLV(TlvCode.ISIS_AREA_IDENTIFIER, Unpooled.wrappedBuffer(isisAreaIdentifier.getValue()), byteAggregator);
546             }
547         }
548         if (nodeAttributes.getIpv4RouterId() != null) {
549             writeTLV(TlvCode.LOCAL_IPV4_ROUTER_ID, Unpooled.wrappedBuffer(InetAddresses.forString(nodeAttributes.getIpv4RouterId().getValue()).getAddress()), byteAggregator);
550         }
551         if (nodeAttributes.getIpv6RouterId() != null) {
552             writeTLV(TlvCode.LOCAL_IPV6_ROUTER_ID, Unpooled.wrappedBuffer(InetAddresses.forString(nodeAttributes.getIpv6RouterId().getValue()).getAddress()), byteAggregator);
553         }
554         LOG.trace("Finished serializing Node Attributes");
555     }
556
557     private static void serializeNodeFlagBits(final NodeFlagBits nodeFlagBits, final ByteBuf byteAggregator) {
558         if (nodeFlagBits != null) {
559             final ByteBuf nodeFlagBuf = Unpooled.buffer();
560             final BitSet flags = new BitSet();
561             if (nodeFlagBits.isOverload() != null) {
562                 flags.set(OVERLOAD_BIT, nodeFlagBits.isOverload());
563             }
564             if (nodeFlagBits.isAttached() != null) {
565                 flags.set(ATTACHED_BIT, nodeFlagBits.isAttached());
566             }
567             if (nodeFlagBits.isExternal() != null) {
568                 flags.set(EXTERNAL_BIT, nodeFlagBits.isExternal());
569             }
570             if (nodeFlagBits.isAbr() != null) {
571                 flags.set(ABBR_BIT, nodeFlagBits.isAbr());
572             }
573             nodeFlagBuf.writeBytes(flags.toByteArray());
574             writeTLV(TlvCode.NODE_FLAG_BITS, nodeFlagBuf, byteAggregator);
575         }
576     }
577
578     private void serializePrefixAttributes(final PrefixAttributesCase prefixAttributesCase, final ByteBuf byteAggregator) {
579         final PrefixAttributes prefixAtrributes = prefixAttributesCase.getPrefixAttributes();
580         if (prefixAtrributes.getIgpBits() != null) {
581             final BitSet igpBit = new BitSet();
582             final Boolean bit = prefixAtrributes.getIgpBits().getUpDown().isUpDown();
583             if (bit != null) {
584                 igpBit.set(UP_DOWN_BIT, bit);
585             }
586             writeTLV(TlvCode.IGP_FLAGS, Unpooled.wrappedBuffer(igpBit.toByteArray()), byteAggregator);
587         }
588         if (prefixAtrributes.getRouteTags() != null) {
589             final ByteBuf routeTagsBuf = Unpooled.buffer();
590             for (final RouteTag routeTag : prefixAtrributes.getRouteTags()) {
591                 routeTagsBuf.writeBytes(routeTag.getValue());
592             }
593             writeTLV(TlvCode.ROUTE_TAG, routeTagsBuf, byteAggregator);
594         }
595         final List<ExtendedRouteTag> routeTagList = prefixAtrributes.getExtendedTags();
596         if (routeTagList != null && !routeTagList.isEmpty()) {
597             final ByteBuf extendedBuf = Unpooled.buffer();
598             for (final ExtendedRouteTag extendedRouteTag : routeTagList) {
599                 extendedBuf.writeBytes(extendedRouteTag.getValue());
600             }
601             writeTLV(TlvCode.EXTENDED_ROUTE_TAG, extendedBuf, byteAggregator);
602         }
603         if (prefixAtrributes.getPrefixMetric() != null) {
604             writeTLV(TlvCode.PREFIX_METRIC, Unpooled.copyInt(prefixAtrributes.getPrefixMetric().getValue().intValue()), byteAggregator);
605         }
606         serializeForwardingAddress(prefixAtrributes.getOspfForwardingAddress(), byteAggregator);
607     }
608
609     private static void serializeForwardingAddress(final IpAddress forwardingAddress, final ByteBuf byteAggregator) {
610         if (forwardingAddress != null) {
611             final ByteBuf ospfBuf = Unpooled.buffer();
612             if (forwardingAddress.getIpv4Address() != null) {
613                 ospfBuf.writeBytes(Ipv4Util.bytesForAddress(forwardingAddress.getIpv4Address()));
614             } else if (forwardingAddress.getIpv6Address() != null) {
615                 ospfBuf.writeBytes(Ipv6Util.bytesForAddress(forwardingAddress.getIpv6Address()));
616             }
617             writeTLV(TlvCode.FORWARDING_ADDRESS, ospfBuf, byteAggregator);
618         }
619     }
620
621     /**
622      * Util method for writing TLV header.
623      * @param type TLV type
624      * @param value TLV value
625      * @param byteAggregator final ByteBuf where the tlv should be serialized
626      */
627     protected static void writeTLV(final int type, final ByteBuf value, final ByteBuf byteAggregator){
628         byteAggregator.writeShort(type);
629         byteAggregator.writeShort(value.writerIndex());
630         byteAggregator.writeBytes(value);
631         value.readerIndex(0);
632         LOG.debug("Serialized tlv type {} to: {}", type, ByteBufUtil.hexDump(value));
633     }
634 }