d9ac893108b98ce9a298e21077fa730abd942429
[bgpcep.git] / bgp / linkstate / src / main / java / org / opendaylight / protocol / bgp / linkstate / LinkstateNlriParser.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.collect.Lists;
11 import com.google.common.primitives.UnsignedBytes;
12 import com.google.common.primitives.UnsignedInteger;
13
14 import io.netty.buffer.ByteBuf;
15 import io.netty.buffer.Unpooled;
16
17 import java.math.BigInteger;
18 import java.util.Arrays;
19 import java.util.List;
20
21 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
22 import org.opendaylight.protocol.bgp.parser.spi.NlriParser;
23 import org.opendaylight.protocol.bgp.parser.spi.NlriUtil;
24 import org.opendaylight.protocol.concepts.Ipv4Util;
25 import org.opendaylight.protocol.concepts.Ipv6Util;
26 import org.opendaylight.protocol.util.ByteArray;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.AreaIdentifier;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.DomainIdentifier;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.Identifier;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.Ipv4InterfaceIdentifier;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.Ipv6InterfaceIdentifier;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.NlriType;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.NodeIdentifier;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.OspfInterfaceIdentifier;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.OspfRouteType;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.ProtocolId;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.RouteDistinguisher;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.TopologyIdentifier;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.isis.lan.identifier.IsIsRouterIdentifier;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.isis.lan.identifier.IsIsRouterIdentifierBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.linkstate.destination.CLinkstateDestination;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.linkstate.destination.CLinkstateDestinationBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.linkstate.destination.c.linkstate.destination.LinkDescriptors;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.linkstate.destination.c.linkstate.destination.LinkDescriptorsBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.linkstate.destination.c.linkstate.destination.LocalNodeDescriptors;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.linkstate.destination.c.linkstate.destination.LocalNodeDescriptorsBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.linkstate.destination.c.linkstate.destination.PrefixDescriptors;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.linkstate.destination.c.linkstate.destination.PrefixDescriptorsBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.linkstate.destination.c.linkstate.destination.RemoteNodeDescriptors;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.linkstate.destination.c.linkstate.destination.RemoteNodeDescriptorsBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.CRouterIdentifier;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.c.router.identifier.IsisNodeCase;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.c.router.identifier.IsisNodeCaseBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.c.router.identifier.IsisPseudonodeCase;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.c.router.identifier.IsisPseudonodeCaseBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.c.router.identifier.OspfNodeCase;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.c.router.identifier.OspfNodeCaseBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.c.router.identifier.OspfPseudonodeCase;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.c.router.identifier.OspfPseudonodeCaseBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.c.router.identifier.isis.node._case.IsisNode;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.c.router.identifier.isis.node._case.IsisNodeBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.c.router.identifier.isis.pseudonode._case.IsisPseudonode;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.c.router.identifier.isis.pseudonode._case.IsisPseudonodeBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.c.router.identifier.ospf.node._case.OspfNodeBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.c.router.identifier.ospf.pseudonode._case.OspfPseudonode;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.node.identifier.c.router.identifier.ospf.pseudonode._case.OspfPseudonodeBuilder;
69 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.DestinationLinkstateCaseBuilder;
70 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.destination.linkstate._case.DestinationLinkstateBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlriBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlriBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.IsoSystemIdentifier;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
78
79 /**
80  * Parser and serializer for Linkstate NLRI.
81  */
82 public final class LinkstateNlriParser implements NlriParser {
83     private static final Logger LOG = LoggerFactory.getLogger(LinkstateNlriParser.class);
84     private static final int ROUTE_DISTINGUISHER_LENGTH = 8;
85     private static final int PROTOCOL_ID_LENGTH = 1;
86     private static final int IDENTIFIER_LENGTH = 8;
87     private static final int LINK_IDENTIFIER_LENGTH = 4;
88     private static final int ISO_SYSTEM_ID_LENGTH = 6;
89     private static final int PSN_LENGTH = 1;
90
91     private static final int TYPE_LENGTH = 2;
92     private static final int LENGTH_SIZE = 2;
93
94     private final boolean isVpn;
95
96     public LinkstateNlriParser(final boolean isVpn) {
97         this.isVpn = isVpn;
98     }
99
100     private static NodeIdentifier parseLink(final CLinkstateDestinationBuilder builder, final ByteBuf buffer) throws BGPParsingException {
101         final int type = buffer.readUnsignedShort();
102         final int length = buffer.readUnsignedShort();
103         final NodeIdentifier remote = null;
104         if (type == TlvCode.REMOTE_NODE_DESCRIPTORS) {
105             builder.setRemoteNodeDescriptors((RemoteNodeDescriptors) parseNodeDescriptors(buffer.slice(buffer.readerIndex(), length), false));
106             buffer.skipBytes(length);
107         }
108         builder.setLinkDescriptors(parseLinkDescriptors(buffer.slice()));
109         return remote;
110     }
111
112     private static LinkDescriptors parseLinkDescriptors(final ByteBuf buffer) throws BGPParsingException {
113         final LinkDescriptorsBuilder builder = new LinkDescriptorsBuilder();
114         while (buffer.isReadable()) {
115             final int type = buffer.readUnsignedShort();
116             final int length = buffer.readUnsignedShort();
117             final byte[] value = ByteArray.readBytes(buffer, length);
118             LOG.trace("Parsing Link Descriptor: {}", Arrays.toString(value));
119             switch (type) {
120             case TlvCode.LINK_LR_IDENTIFIERS:
121                 builder.setLinkLocalIdentifier(ByteArray.bytesToUint32(ByteArray.subByte(value, 0, LINK_IDENTIFIER_LENGTH)).longValue());
122                 builder.setLinkRemoteIdentifier(ByteArray.bytesToUint32(
123                         ByteArray.subByte(value, LINK_IDENTIFIER_LENGTH, LINK_IDENTIFIER_LENGTH)).longValue());
124                 LOG.debug("Parsed link local {} remote {} Identifiers.", builder.getLinkLocalIdentifier(),
125                         builder.getLinkRemoteIdentifier());
126                 break;
127             case TlvCode.IPV4_IFACE_ADDRESS:
128                 final Ipv4InterfaceIdentifier lipv4 = new Ipv4InterfaceIdentifier(Ipv4Util.addressForBytes(value));
129                 builder.setIpv4InterfaceAddress(lipv4);
130                 LOG.debug("Parsed IPv4 interface address {}.", lipv4);
131                 break;
132             case TlvCode.IPV4_NEIGHBOR_ADDRESS:
133                 final Ipv4InterfaceIdentifier ripv4 = new Ipv4InterfaceIdentifier(Ipv4Util.addressForBytes(value));
134                 builder.setIpv4NeighborAddress(ripv4);
135                 LOG.debug("Parsed IPv4 neighbor address {}.", ripv4);
136                 break;
137             case TlvCode.IPV6_IFACE_ADDRESS:
138                 final Ipv6InterfaceIdentifier lipv6 = new Ipv6InterfaceIdentifier(Ipv6Util.addressForBytes(value));
139                 builder.setIpv6InterfaceAddress(lipv6);
140                 LOG.debug("Parsed IPv6 interface address {}.", lipv6);
141                 break;
142             case TlvCode.IPV6_NEIGHBOR_ADDRESS:
143                 final Ipv6InterfaceIdentifier ripv6 = new Ipv6InterfaceIdentifier(Ipv6Util.addressForBytes(value));
144                 builder.setIpv6NeighborAddress(ripv6);
145                 LOG.debug("Parsed IPv6 neighbor address {}.", ripv6);
146                 break;
147             case TlvCode.MULTI_TOPOLOGY_ID:
148                 final TopologyIdentifier topId = new TopologyIdentifier(ByteArray.bytesToInt(value) & 0x3fff);
149                 builder.setMultiTopologyId(topId);
150                 LOG.debug("Parsed topology identifier {}.", topId);
151                 break;
152             default:
153                 throw new BGPParsingException("Link Descriptor not recognized, type: " + type);
154             }
155         }
156         LOG.trace("Finished parsing Link descriptors.");
157         return builder.build();
158     }
159
160     private static NodeIdentifier parseNodeDescriptors(final ByteBuf buffer, final boolean local) throws BGPParsingException {
161         AsNumber asnumber = null;
162         DomainIdentifier bgpId = null;
163         AreaIdentifier ai = null;
164         CRouterIdentifier routerId = null;
165         while (buffer.isReadable()) {
166             final int type = buffer.readUnsignedShort();
167             final int length = buffer.readUnsignedShort();
168             final byte[] value = ByteArray.readBytes(buffer, length);
169             LOG.trace("Parsing Node Descriptor: {}", Arrays.toString(value));
170             switch (type) {
171             case TlvCode.AS_NUMBER:
172                 asnumber = new AsNumber(ByteArray.bytesToLong(value));
173                 LOG.debug("Parsed {}", asnumber);
174                 break;
175             case TlvCode.BGP_LS_ID:
176                 bgpId = new DomainIdentifier(UnsignedInteger.fromIntBits(ByteArray.bytesToInt(value)).longValue());
177                 LOG.debug("Parsed {}", bgpId);
178                 break;
179             case TlvCode.AREA_ID:
180                 ai = new AreaIdentifier(UnsignedInteger.fromIntBits(ByteArray.bytesToInt(value)).longValue());
181                 LOG.debug("Parsed area identifier {}", ai);
182                 break;
183             case TlvCode.IGP_ROUTER_ID:
184                 routerId = parseRouterId(value);
185                 LOG.debug("Parsed Router Identifier {}", routerId);
186                 break;
187             default:
188                 throw new BGPParsingException("Node Descriptor not recognized, type: " + type);
189             }
190         }
191         LOG.trace("Finished parsing Node descriptors.");
192         return (local) ? new LocalNodeDescriptorsBuilder().setAsNumber(asnumber).setDomainId(bgpId).setAreaId(ai).setCRouterIdentifier(
193                 routerId).build()
194                 : new RemoteNodeDescriptorsBuilder().setAsNumber(asnumber).setDomainId(bgpId).setAreaId(ai).setCRouterIdentifier(routerId).build();
195     }
196
197     private static CRouterIdentifier parseRouterId(final byte[] value) throws BGPParsingException {
198         if (value.length == ISO_SYSTEM_ID_LENGTH) {
199             return new IsisNodeCaseBuilder().setIsisNode(
200                     new IsisNodeBuilder().setIsoSystemId(new IsoSystemIdentifier(ByteArray.subByte(value, 0, ISO_SYSTEM_ID_LENGTH))).build()).build();
201         }
202         if (value.length == ISO_SYSTEM_ID_LENGTH + PSN_LENGTH) {
203             if (value[ISO_SYSTEM_ID_LENGTH] == 0) {
204                 LOG.warn("PSN octet is 0. Ignoring System ID.");
205                 return new IsisNodeCaseBuilder().setIsisNode(
206                         new IsisNodeBuilder().setIsoSystemId(new IsoSystemIdentifier(ByteArray.subByte(value, 0, ISO_SYSTEM_ID_LENGTH))).build()).build();
207             } else {
208                 final IsIsRouterIdentifier iri = new IsIsRouterIdentifierBuilder().setIsoSystemId(
209                         new IsoSystemIdentifier(ByteArray.subByte(value, 0, ISO_SYSTEM_ID_LENGTH))).build();
210                 return new IsisPseudonodeCaseBuilder().setIsisPseudonode(
211                         new IsisPseudonodeBuilder().setIsIsRouterIdentifier(iri).setPsn(
212                                 (short) UnsignedBytes.toInt(value[ISO_SYSTEM_ID_LENGTH])).build()).build();
213             }
214         }
215         if (value.length == 4) {
216             return new OspfNodeCaseBuilder().setOspfNode(
217                     new OspfNodeBuilder().setOspfRouterId(ByteArray.bytesToUint32(value).longValue()).build()).build();
218         }
219         if (value.length == 8) {
220             final byte[] o = ByteArray.subByte(value, 0, 4);
221             final OspfInterfaceIdentifier a = new OspfInterfaceIdentifier(ByteArray.bytesToUint32(ByteArray.subByte(value, 4, 4)).longValue());
222             return new OspfPseudonodeCaseBuilder().setOspfPseudonode(
223                     new OspfPseudonodeBuilder().setOspfRouterId(ByteArray.bytesToUint32(o).longValue()).setLanInterface(a).build()).build();
224         }
225         throw new BGPParsingException("Router Id of invalid length " + value.length);
226     }
227
228     private static PrefixDescriptors parsePrefixDescriptors(final ByteBuf buffer, final boolean ipv4) throws BGPParsingException {
229         final PrefixDescriptorsBuilder builder = new PrefixDescriptorsBuilder();
230         while (buffer.isReadable()) {
231             final int type = buffer.readUnsignedShort();
232             final int length = buffer.readUnsignedShort();
233             final byte[] value = ByteArray.readBytes(buffer, length);
234             LOG.trace("Parsing Prefix Descriptor: {}", Arrays.toString(value));
235             switch (type) {
236             case TlvCode.MULTI_TOPOLOGY_ID:
237                 final TopologyIdentifier topologyId = new TopologyIdentifier(ByteArray.bytesToInt(value) & 0x3fff);
238                 builder.setMultiTopologyId(topologyId);
239                 LOG.trace("Parsed Topology Identifier: {}", topologyId);
240                 break;
241             case TlvCode.OSPF_ROUTE_TYPE:
242                 final int rt = ByteArray.bytesToInt(value);
243                 final OspfRouteType routeType = OspfRouteType.forValue(rt);
244                 if (routeType == null) {
245                     throw new BGPParsingException("Unknown OSPF Route Type: " + rt);
246                 }
247                 builder.setOspfRouteType(routeType);
248                 LOG.trace("Parser RouteType: {}", routeType);
249                 break;
250             case TlvCode.IP_REACHABILITY:
251                 IpPrefix prefix = null;
252                 final int prefixLength = UnsignedBytes.toInt(value[0]);
253                 final int size = prefixLength / Byte.SIZE + ((prefixLength % Byte.SIZE == 0) ? 0 : 1);
254                 if (size != value.length - 1) {
255                     LOG.debug("Expected length {}, actual length {}.", size, value.length - 1);
256                     throw new BGPParsingException("Illegal length of IP reachability TLV: " + (value.length - 1));
257                 }
258                 if (ipv4) {
259                     prefix = new IpPrefix(Ipv4Util.prefixForBytes(ByteArray.subByte(value, 1, size), prefixLength));
260                 } else {
261                     prefix = new IpPrefix(Ipv6Util.prefixForBytes(ByteArray.subByte(value, 1, size), prefixLength));
262                 }
263                 builder.setIpReachabilityInformation(prefix);
264                 LOG.trace("Parsed IP reachability info: {}", prefix);
265                 break;
266             default:
267                 throw new BGPParsingException("Prefix Descriptor not recognized, type: " + type);
268             }
269         }
270         LOG.debug("Finished parsing Prefix descriptors.");
271         return builder.build();
272     }
273
274     /**
275      * Parses common parts for Link State Nodes, Links and Prefixes, that includes protocol ID and identifier tlv.
276      *
277      * @param nlri as byte array
278      * @return {@link CLinkstateDestination}
279      * @throws BGPParsingException if parsing was unsuccessful
280      */
281     private List<CLinkstateDestination> parseNlri(final ByteBuf nlri) throws BGPParsingException {
282         if (!nlri.isReadable()) {
283             return null;
284         }
285         final List<CLinkstateDestination> dests = Lists.newArrayList();
286
287         CLinkstateDestinationBuilder builder = null;
288
289         while (nlri.isReadable()) {
290             builder = new CLinkstateDestinationBuilder();
291             final NlriType type = NlriType.forValue(nlri.readUnsignedShort());
292             builder.setNlriType(type);
293
294             // length means total length of the tlvs including route distinguisher not including the type field
295             final int length = nlri.readUnsignedShort();
296             RouteDistinguisher distinguisher = null;
297             if (this.isVpn) {
298                 // this parses route distinguisher
299                 distinguisher = new RouteDistinguisher(BigInteger.valueOf(nlri.readLong()));
300                 builder.setDistinguisher(distinguisher);
301             }
302             // parse source protocol
303             final ProtocolId sp = ProtocolId.forValue(UnsignedBytes.toInt(nlri.readByte()));
304             builder.setProtocolId(sp);
305
306             // parse identifier
307             final Identifier identifier = new Identifier(BigInteger.valueOf(nlri.readLong()));
308             builder.setIdentifier(identifier);
309
310             // if we are dealing with linkstate nodes/links, parse local node descriptor
311             NodeIdentifier localDescriptor = null;
312             int locallength = 0;
313             final int localtype = nlri.readUnsignedShort();
314             locallength = nlri.readUnsignedShort();
315             if (localtype == TlvCode.LOCAL_NODE_DESCRIPTORS) {
316                 localDescriptor = parseNodeDescriptors(nlri.slice(nlri.readerIndex(), locallength), true);
317             }
318             nlri.skipBytes(locallength);
319             builder.setLocalNodeDescriptors((LocalNodeDescriptors) localDescriptor);
320             final int restLength = length - (this.isVpn ? ROUTE_DISTINGUISHER_LENGTH : 0) - PROTOCOL_ID_LENGTH - IDENTIFIER_LENGTH
321                     - TYPE_LENGTH - LENGTH_SIZE - locallength;
322             LOG.trace("Restlength {}", restLength);
323             ByteBuf rest = nlri.slice(nlri.readerIndex(), restLength);
324             switch (type) {
325             case Link:
326                 parseLink(builder, rest);
327                 break;
328             case Ipv4Prefix:
329                 builder.setPrefixDescriptors(parsePrefixDescriptors(rest, true));
330                 break;
331             case Ipv6Prefix:
332                 builder.setPrefixDescriptors(parsePrefixDescriptors(rest, false));
333                 break;
334             case Node:
335                 // node nlri is already parsed as it contains only the common fields for node and link nlri
336                 break;
337             }
338             nlri.skipBytes(restLength);
339             dests.add(builder.build());
340         }
341         return dests;
342     }
343
344     @Override
345     public void parseNlri(final ByteBuf nlri, final MpUnreachNlriBuilder builder) throws BGPParsingException {
346         if (!nlri.isReadable()) {
347             return;
348         }
349         final List<CLinkstateDestination> dst = parseNlri(nlri);
350
351         builder.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(
352                 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationLinkstateCaseBuilder().setDestinationLinkstate(
353                         new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev131125.update.path.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.destination.linkstate._case.DestinationLinkstateBuilder().setCLinkstateDestination(
354                                 dst).build()).build()).build());
355     }
356
357     @Override
358     public void parseNlri(final ByteBuf nlri, final byte[] nextHop, final MpReachNlriBuilder builder) throws BGPParsingException {
359         if (!nlri.isReadable()) {
360             return;
361         }
362         final List<CLinkstateDestination> dst = parseNlri(nlri);
363
364         builder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(
365                 new DestinationLinkstateCaseBuilder().setDestinationLinkstate(
366                         new DestinationLinkstateBuilder().setCLinkstateDestination(dst).build()).build()).build());
367         NlriUtil.parseNextHop(nextHop, builder);
368     }
369
370     /**
371      * Serializes Linkstate NLRI to byte array. We need this as NLRI serves as a key in upper layers.
372      *
373      * @param destination Linkstate NLRI to be serialized
374      * @return byte array
375      */
376     public static byte[] serializeNlri(final CLinkstateDestination destination) {
377         final ByteBuf finalBuffer = Unpooled.buffer();
378         finalBuffer.writeShort(destination.getNlriType().getIntValue());
379         final ByteBuf buffer = Unpooled.buffer();
380         if (destination.getDistinguisher() != null) {
381             buffer.writeBytes(destination.getDistinguisher().getValue().toByteArray());
382         }
383         buffer.writeByte(destination.getProtocolId().getIntValue());
384         buffer.writeBytes(ByteArray.longToBytes(destination.getIdentifier().getValue().longValue(), IDENTIFIER_LENGTH));
385
386         // serialize local node descriptors
387         final byte[] ldescs = serializeNodeDescriptors(destination.getLocalNodeDescriptors());
388         buffer.writeShort(TlvCode.LOCAL_NODE_DESCRIPTORS);
389         buffer.writeShort(ldescs.length);
390         buffer.writeBytes(ldescs);
391
392         switch (destination.getNlriType()) {
393         case Ipv4Prefix:
394         case Ipv6Prefix:
395             if (destination.getPrefixDescriptors() != null) {
396                 serializePrefixDescriptors(buffer, destination.getPrefixDescriptors());
397             }
398             break;
399         case Link:
400             final byte[] rdescs = serializeNodeDescriptors(destination.getRemoteNodeDescriptors());
401             buffer.writeShort(TlvCode.REMOTE_NODE_DESCRIPTORS);
402             buffer.writeShort(rdescs.length);
403             buffer.writeBytes(rdescs);
404             if (destination.getLinkDescriptors() != null) {
405                 serializeLinkDescriptors(buffer, destination.getLinkDescriptors());
406             }
407             break;
408         case Node:
409             break;
410         default:
411             LOG.warn("Unknown NLRI Type.");
412             break;
413         }
414         finalBuffer.writeShort(buffer.readableBytes());
415         finalBuffer.writeBytes(buffer);
416         return ByteArray.subByte(finalBuffer.array(), 0, finalBuffer.readableBytes());
417     }
418
419     private static byte[] serializeNodeDescriptors(final NodeIdentifier descriptors) {
420         final ByteBuf buffer = Unpooled.buffer();
421         final int length = Integer.SIZE / Byte.SIZE;
422         if (descriptors.getAsNumber() != null) {
423             buffer.writeShort(TlvCode.AS_NUMBER);
424             buffer.writeShort(length);
425             buffer.writeInt(UnsignedInteger.valueOf(descriptors.getAsNumber().getValue()).intValue());
426         }
427         if (descriptors.getDomainId() != null) {
428             buffer.writeShort(TlvCode.BGP_LS_ID);
429             buffer.writeShort(length);
430             buffer.writeInt(UnsignedInteger.valueOf(descriptors.getDomainId().getValue()).intValue());
431         }
432         if (descriptors.getAreaId() != null) {
433             buffer.writeShort(TlvCode.AREA_ID);
434             buffer.writeShort(length);
435             buffer.writeInt(UnsignedInteger.valueOf(descriptors.getAreaId().getValue()).intValue());
436         }
437         if (descriptors.getCRouterIdentifier() != null) {
438             final byte[] value = serializeRouterId(descriptors.getCRouterIdentifier());
439             buffer.writeShort(TlvCode.IGP_ROUTER_ID);
440             buffer.writeShort(value.length);
441             buffer.writeBytes(value);
442         }
443         return ByteArray.readAllBytes(buffer);
444     }
445
446     private static byte[] serializeRouterId(final CRouterIdentifier routerId) {
447         byte[] bytes = null;
448         if (routerId instanceof IsisNodeCase) {
449             final IsisNode isis = ((IsisNodeCase) routerId).getIsisNode();
450             bytes = isis.getIsoSystemId().getValue();
451         } else if (routerId instanceof IsisPseudonodeCase) {
452             bytes = new byte[ISO_SYSTEM_ID_LENGTH + PSN_LENGTH];
453             final IsisPseudonode isis = ((IsisPseudonodeCase) routerId).getIsisPseudonode();
454             ByteArray.copyWhole(isis.getIsIsRouterIdentifier().getIsoSystemId().getValue(), bytes, 0);
455             bytes[6] = UnsignedBytes.checkedCast((isis.getPsn() != null) ? isis.getPsn() : 0);
456         } else if (routerId instanceof OspfNodeCase) {
457             bytes = ByteArray.uint32ToBytes(((OspfNodeCase) routerId).getOspfNode().getOspfRouterId());
458         } else if (routerId instanceof OspfPseudonodeCase) {
459             final OspfPseudonode node = ((OspfPseudonodeCase) routerId).getOspfPseudonode();
460             bytes = new byte[2 * Integer.SIZE / Byte.SIZE];
461             ByteArray.copyWhole(ByteArray.uint32ToBytes(node.getOspfRouterId()), bytes, 0);
462             ByteArray.copyWhole(ByteArray.uint32ToBytes(node.getLanInterface().getValue()), bytes, Integer.SIZE / Byte.SIZE);
463         }
464         return bytes;
465     }
466
467     private static void serializeLinkDescriptors(final ByteBuf buffer, final LinkDescriptors descriptors) {
468         if (descriptors.getLinkLocalIdentifier() != null && descriptors.getLinkRemoteIdentifier() != null) {
469             buffer.writeShort(TlvCode.LINK_LR_IDENTIFIERS);
470             buffer.writeShort(LINK_IDENTIFIER_LENGTH);
471             buffer.writeInt(UnsignedInteger.valueOf(descriptors.getLinkLocalIdentifier()).intValue());
472             buffer.writeInt(UnsignedInteger.valueOf(descriptors.getLinkRemoteIdentifier()).intValue());
473         }
474         if (descriptors.getIpv4InterfaceAddress() != null) {
475             final byte[] ipv4Address = Ipv4Util.bytesForAddress(descriptors.getIpv4InterfaceAddress());
476             buffer.writeShort(TlvCode.IPV4_IFACE_ADDRESS);
477             buffer.writeShort(ipv4Address.length);
478             buffer.writeBytes(ipv4Address);
479         }
480         if (descriptors.getIpv4NeighborAddress() != null) {
481             final byte[] ipv4Address = Ipv4Util.bytesForAddress(descriptors.getIpv4NeighborAddress());
482             buffer.writeShort(TlvCode.IPV4_NEIGHBOR_ADDRESS);
483             buffer.writeShort(ipv4Address.length);
484             buffer.writeBytes(ipv4Address);
485         }
486         if (descriptors.getIpv6InterfaceAddress() != null) {
487             final byte[] ipv6Address = Ipv6Util.bytesForAddress(descriptors.getIpv6InterfaceAddress());
488             buffer.writeShort(TlvCode.IPV6_IFACE_ADDRESS);
489             buffer.writeShort(ipv6Address.length);
490             buffer.writeBytes(ipv6Address);
491         }
492         if (descriptors.getIpv6NeighborAddress() != null) {
493             final byte[] ipv6Address = Ipv6Util.bytesForAddress(descriptors.getIpv6NeighborAddress());
494             buffer.writeShort(TlvCode.IPV6_NEIGHBOR_ADDRESS);
495             buffer.writeShort(ipv6Address.length);
496             buffer.writeBytes(ipv6Address);
497         }
498         if (descriptors.getMultiTopologyId() != null) {
499             buffer.writeShort(TlvCode.MULTI_TOPOLOGY_ID);
500             buffer.writeShort(Short.SIZE / Byte.SIZE);
501             buffer.writeShort(descriptors.getMultiTopologyId().getValue());
502         }
503     }
504
505     private static void serializePrefixDescriptors(final ByteBuf buffer, final PrefixDescriptors descriptors) {
506         if (descriptors.getMultiTopologyId() != null) {
507             buffer.writeShort(TlvCode.MULTI_TOPOLOGY_ID);
508             buffer.writeShort(Short.SIZE / Byte.SIZE);
509             buffer.writeShort(descriptors.getMultiTopologyId().getValue());
510         }
511         if (descriptors.getOspfRouteType() != null) {
512             buffer.writeShort(TlvCode.OSPF_ROUTE_TYPE);
513             buffer.writeShort(1);
514             buffer.writeByte(descriptors.getOspfRouteType().getIntValue());
515         }
516         if (descriptors.getIpReachabilityInformation() != null) {
517             final IpPrefix prefix = descriptors.getIpReachabilityInformation();
518             byte[] prefixBytes = null;
519             final int prefixLength = Ipv4Util.getPrefixLength(prefix);
520             if (prefix.getIpv4Prefix() != null) {
521                 prefixBytes = ByteArray.trim(ByteArray.subByte(Ipv4Util.bytesForPrefix(prefix.getIpv4Prefix()), 0,
522                         Ipv4Util.bytesForPrefix(prefix.getIpv4Prefix()).length - 1));
523             } else if (prefix.getIpv6Prefix() != null) {
524                 prefixBytes = ByteArray.trim(ByteArray.subByte(Ipv6Util.bytesForPrefix(prefix.getIpv6Prefix()), 0,
525                         Ipv6Util.bytesForPrefix(prefix.getIpv6Prefix()).length - 1));
526             }
527             buffer.writeShort(TlvCode.IP_REACHABILITY);
528             buffer.writeShort(1 + prefixBytes.length);
529             buffer.writeByte(prefixLength);
530             buffer.writeBytes(prefixBytes);
531         }
532     }
533 }