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