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