BUG-2982 : moved path-attributes container to grouping
[bgpcep.git] / bgp / linkstate / src / main / java / org / opendaylight / protocol / bgp / linkstate / nlri / 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.nlri;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import io.netty.buffer.ByteBuf;
13 import io.netty.buffer.Unpooled;
14 import java.math.BigInteger;
15 import java.util.ArrayList;
16 import java.util.List;
17 import org.opendaylight.protocol.bgp.linkstate.spi.TlvUtil;
18 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
19 import org.opendaylight.protocol.bgp.parser.spi.NlriParser;
20 import org.opendaylight.protocol.bgp.parser.spi.NlriSerializer;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.Identifier;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.NlriType;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.ProtocolId;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.RouteDistinguisher;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.ObjectType;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.destination.CLinkstateDestination;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.destination.CLinkstateDestinationBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.LinkCase;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.LinkCaseBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.NodeCase;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.NodeCaseBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.PrefixCase;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.PrefixCaseBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.link._case.LinkDescriptors;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.link._case.LocalNodeDescriptors;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.link._case.RemoteNodeDescriptors;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.node._case.NodeDescriptors;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.prefix._case.AdvertisingNodeDescriptors;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.prefix._case.PrefixDescriptors;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLinkstateCaseBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.update.attributes.mp.reach.nlri.advertized.routes.destination.type.destination.linkstate._case.DestinationLinkstateBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationLinkstateCase;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Attributes;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes1;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlriBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlri;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlriBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutes;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
52 import org.opendaylight.yangtools.yang.binding.DataObject;
53 import org.opendaylight.yangtools.yang.common.QName;
54 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
55 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
56 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
57 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
58 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
59 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62
63 /**
64  * Parser and serializer for Linkstate NLRI.
65  */
66 public final class LinkstateNlriParser implements NlriParser, NlriSerializer {
67
68     private static final Logger LOG = LoggerFactory.getLogger(LinkstateNlriParser.class);
69
70     private static final int ROUTE_DISTINGUISHER_LENGTH = 8;
71     private static final int PROTOCOL_ID_LENGTH = 1;
72     private static final int IDENTIFIER_LENGTH = 8;
73
74     private static final int TYPE_LENGTH = 2;
75     private static final int LENGTH_SIZE = 2;
76
77     private static final int LOCAL_NODE_DESCRIPTORS_TYPE = 256;
78     private static final int REMOTE_NODE_DESCRIPTORS_TYPE = 257;
79
80     private static final NodeIdentifier OBJECT_TYPE_NID = new NodeIdentifier(ObjectType.QNAME);
81     private static final NodeIdentifier NODE_DESCRIPTORS_NID = new NodeIdentifier(NodeDescriptors.QNAME);
82     private static final NodeIdentifier LOCAL_NODE_DESCRIPTORS_NID = new NodeIdentifier(LocalNodeDescriptors.QNAME);
83     private static final NodeIdentifier REMOTE_NODE_DESCRIPTORS_NID = new NodeIdentifier(RemoteNodeDescriptors.QNAME);
84     private static final NodeIdentifier ADVERTISING_NODE_DESCRIPTORS_NID = new NodeIdentifier(AdvertisingNodeDescriptors.QNAME);
85
86     private static final NodeIdentifier DISTINGUISHER_NID = new NodeIdentifier(QName.cachedReference(QName.create(CLinkstateDestination.QNAME, "route-distinguisher")));
87     private static final NodeIdentifier PROTOCOL_ID_NID = new NodeIdentifier(QName.cachedReference(QName.create(CLinkstateDestination.QNAME, "protocol-id")));
88     private static final NodeIdentifier IDENTIFIER_NID = new NodeIdentifier(QName.cachedReference(QName.create(CLinkstateDestination.QNAME, "identifier")));
89
90     private final boolean isVpn;
91
92     public LinkstateNlriParser(final boolean isVpn) {
93         this.isVpn = isVpn;
94     }
95
96     private static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.NodeIdentifier parseLink(final CLinkstateDestinationBuilder builder, final ByteBuf buffer, final LocalNodeDescriptors localDescriptors)
97             throws BGPParsingException {
98         final int type = buffer.readUnsignedShort();
99         final int length = buffer.readUnsignedShort();
100         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.NodeIdentifier remote = null;
101         RemoteNodeDescriptors remoteDescriptors = null;
102         if (type == REMOTE_NODE_DESCRIPTORS_TYPE) {
103             remoteDescriptors = (RemoteNodeDescriptors)NodeNlriParser.parseNodeDescriptors(buffer.readSlice(length), NlriType.Link, false);
104         }
105         builder.setObjectType(new LinkCaseBuilder()
106             .setLocalNodeDescriptors(localDescriptors)
107             .setRemoteNodeDescriptors(remoteDescriptors)
108             .setLinkDescriptors(LinkNlriParser.parseLinkDescriptors(buffer.slice())).build());
109         return remote;
110     }
111
112     /**
113      * Parses common parts for Link State Nodes, Links and Prefixes, that includes protocol ID and identifier tlv.
114      *
115      * @param nlri as byte array
116      * @param isVpn flag which determines that destination has route distinguisher
117      * @return {@link CLinkstateDestination}
118      * @throws BGPParsingException if parsing was unsuccessful
119      */
120     public static List<CLinkstateDestination> parseNlri(final ByteBuf nlri, final boolean isVpn) throws BGPParsingException {
121         final List<CLinkstateDestination> dests = new ArrayList<>();
122         while (nlri.isReadable()) {
123             final CLinkstateDestinationBuilder builder = new CLinkstateDestinationBuilder();
124             final NlriType type = NlriType.forValue(nlri.readUnsignedShort());
125
126             // length means total length of the tlvs including route distinguisher not including the type field
127             final int length = nlri.readUnsignedShort();
128             RouteDistinguisher distinguisher = null;
129             if (isVpn) {
130                 // this parses route distinguisher
131                 distinguisher = new RouteDistinguisher(BigInteger.valueOf(nlri.readLong()));
132                 builder.setDistinguisher(distinguisher);
133             }
134             // parse source protocol
135             final ProtocolId sp = ProtocolId.forValue(nlri.readByte());
136             builder.setProtocolId(sp);
137
138             // parse identifier
139             final Identifier identifier = new Identifier(BigInteger.valueOf(nlri.readLong()));
140             builder.setIdentifier(identifier);
141
142             // if we are dealing with linkstate nodes/links, parse local node descriptor
143             org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.NodeIdentifier localDescriptor = null;
144             final int localtype = nlri.readUnsignedShort();
145             final int locallength = nlri.readUnsignedShort();
146             if (localtype == LOCAL_NODE_DESCRIPTORS_TYPE) {
147                 localDescriptor = NodeNlriParser.parseNodeDescriptors(nlri.readSlice(locallength), type, true);
148             }
149             final int restLength = length - (isVpn ? ROUTE_DISTINGUISHER_LENGTH : 0) - PROTOCOL_ID_LENGTH - IDENTIFIER_LENGTH
150                 - TYPE_LENGTH - LENGTH_SIZE - locallength;
151             LOG.trace("Restlength {}", restLength);
152             final ByteBuf rest = nlri.readSlice(restLength);
153             switch (type) {
154             case Link:
155                 parseLink(builder, rest, (LocalNodeDescriptors) localDescriptor);
156                 break;
157             case Ipv4Prefix:
158                 builder.setObjectType(new PrefixCaseBuilder()
159                     .setAdvertisingNodeDescriptors((AdvertisingNodeDescriptors)localDescriptor)
160                     .setPrefixDescriptors(PrefixNlriParser.parsePrefixDescriptors(rest, true)).build());
161                 break;
162             case Ipv6Prefix:
163                 builder.setObjectType(new PrefixCaseBuilder()
164                     .setAdvertisingNodeDescriptors((AdvertisingNodeDescriptors)localDescriptor)
165                     .setPrefixDescriptors(PrefixNlriParser.parsePrefixDescriptors(rest, false)).build());
166                 break;
167             case Node:
168                 // node nlri is already parsed as it contains only the common fields for node and link nlri
169                 builder.setObjectType(new NodeCaseBuilder().setNodeDescriptors((NodeDescriptors)localDescriptor).build());
170                 break;
171             default:
172                 break;
173             }
174             dests.add(builder.build());
175         }
176         return dests;
177     }
178
179     @Override
180     public void parseNlri(final ByteBuf nlri, final MpUnreachNlriBuilder builder) throws BGPParsingException {
181         if (!nlri.isReadable()) {
182             return;
183         }
184         final List<CLinkstateDestination> dst = parseNlri(nlri, this.isVpn);
185
186         builder.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(
187             new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationLinkstateCaseBuilder().setDestinationLinkstate(
188                 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.destination.linkstate._case.DestinationLinkstateBuilder().setCLinkstateDestination(
189                     dst).build()).build()).build());
190     }
191
192     @Override
193     public void parseNlri(final ByteBuf nlri, final MpReachNlriBuilder builder) throws BGPParsingException {
194         if (!nlri.isReadable()) {
195             return;
196         }
197         final List<CLinkstateDestination> dst = parseNlri(nlri, this.isVpn);
198
199         builder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(
200             new DestinationLinkstateCaseBuilder().setDestinationLinkstate(
201                 new DestinationLinkstateBuilder().setCLinkstateDestination(dst).build()).build()).build());
202     }
203
204     /**
205      * Serializes Linkstate NLRI to byte array. We need this as NLRI serves as a key in upper layers.
206      *
207      * @param destination Linkstate NLRI to be serialized
208      * @param buffer where Linkstate NLRI will be serialized
209      */
210     public static void serializeNlri(final CLinkstateDestination destination, final ByteBuf buffer) {
211         final ByteBuf nlriByteBuf = Unpooled.buffer();
212         if (destination.getDistinguisher() != null) {
213             nlriByteBuf.writeBytes(destination.getDistinguisher().getValue().toByteArray());
214         }
215         nlriByteBuf.writeByte(destination.getProtocolId().getIntValue());
216         nlriByteBuf.writeLong(destination.getIdentifier().getValue().longValue());
217         final ByteBuf ldescs = Unpooled.buffer();
218         final ObjectType ot = destination.getObjectType();
219         NlriType nlriType = null;
220         if (ot instanceof PrefixCase) {
221             final PrefixCase pCase = (PrefixCase)destination.getObjectType();
222             NodeNlriParser.serializeNodeDescriptors(pCase.getAdvertisingNodeDescriptors(), ldescs);
223             TlvUtil.writeTLV(LOCAL_NODE_DESCRIPTORS_TYPE, ldescs, nlriByteBuf);
224             if (pCase.getPrefixDescriptors() != null) {
225                 PrefixNlriParser.serializePrefixDescriptors(pCase.getPrefixDescriptors(), nlriByteBuf);
226                 if (pCase.getPrefixDescriptors().getIpReachabilityInformation().getIpv4Prefix() != null) {
227                     nlriType = NlriType.Ipv4Prefix;
228                 } else {
229                     nlriType = NlriType.Ipv6Prefix;
230                 }
231             }
232         } else if (ot instanceof LinkCase) {
233             final LinkCase lCase = (LinkCase)destination.getObjectType();
234             NodeNlriParser.serializeNodeDescriptors(lCase.getLocalNodeDescriptors(), ldescs);
235             TlvUtil.writeTLV(LOCAL_NODE_DESCRIPTORS_TYPE, ldescs, nlriByteBuf);
236             final ByteBuf rdescs = Unpooled.buffer();
237             NodeNlriParser.serializeNodeDescriptors(lCase.getRemoteNodeDescriptors(), rdescs);
238             TlvUtil.writeTLV(REMOTE_NODE_DESCRIPTORS_TYPE, rdescs, nlriByteBuf);
239             if (lCase.getLinkDescriptors() != null) {
240                 LinkNlriParser.serializeLinkDescriptors(lCase.getLinkDescriptors(), nlriByteBuf);
241             }
242             nlriType = NlriType.Link;
243         } else if (ot instanceof NodeCase) {
244             final NodeCase nCase = (NodeCase)destination.getObjectType();
245             NodeNlriParser.serializeNodeDescriptors(nCase.getNodeDescriptors(), ldescs);
246             TlvUtil.writeTLV(LOCAL_NODE_DESCRIPTORS_TYPE, ldescs, nlriByteBuf);
247             nlriType = NlriType.Node;
248         } else {
249             LOG.warn("Unknown NLRI Type.");
250         }
251         TlvUtil.writeTLV(nlriType.getIntValue(), nlriByteBuf, buffer);
252     }
253
254     @Override
255     public void serializeAttribute(final DataObject attribute, final ByteBuf byteAggregator) {
256         Preconditions.checkArgument(attribute instanceof Attributes, "Attribute parameter is not a PathAttribute object.");
257         final Attributes pathAttributes = (Attributes) attribute;
258         final Attributes1 pathAttributes1 = pathAttributes.getAugmentation(Attributes1.class);
259         final Attributes2 pathAttributes2 = pathAttributes.getAugmentation(Attributes2.class);
260         if (pathAttributes1 != null) {
261             final AdvertizedRoutes routes = (pathAttributes1.getMpReachNlri()).getAdvertizedRoutes();
262             if (routes != null &&
263                 routes.getDestinationType()
264                 instanceof
265                 org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLinkstateCase) {
266                 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLinkstateCase
267                 linkstateCase = (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLinkstateCase) routes.getDestinationType();
268
269                 for (final CLinkstateDestination cLinkstateDestination : linkstateCase.getDestinationLinkstate().getCLinkstateDestination()) {
270                     serializeNlri(cLinkstateDestination, byteAggregator);
271                 }
272             }
273         } else if (pathAttributes2 != null) {
274             final MpUnreachNlri mpUnreachNlri = pathAttributes2.getMpUnreachNlri();
275             if (mpUnreachNlri.getWithdrawnRoutes() != null && mpUnreachNlri.getWithdrawnRoutes().getDestinationType() instanceof DestinationLinkstateCase) {
276                 final DestinationLinkstateCase linkstateCase = (DestinationLinkstateCase) mpUnreachNlri.getWithdrawnRoutes().getDestinationType();
277                 for (final CLinkstateDestination cLinkstateDestination : linkstateCase.getDestinationLinkstate().getCLinkstateDestination()) {
278                     serializeNlri(cLinkstateDestination, byteAggregator);
279                 }
280             }
281         }
282     }
283
284     private static int domProtocolIdValue(final String protocolId) {
285         switch(protocolId) {
286         case "unknown":
287             return 0;
288         case "isis-level1":
289             return 1;
290         case "isis-level2":
291             return 2;
292         case "ospf":
293             return 3;
294         case "direct":
295             return 4;
296         case "static":
297             return 5;
298         default:
299             return 0;
300         }
301     }
302
303     /**
304      * Serializes DOM interpretation of Linkstate NLRI to ByteBuf. Used to create linkstate route key.
305      *
306      * @param linkstate UnkeyedListEntryNode basically CLinkstateDestination in DOM
307      * @param buffer ByteBuf where the key will be serialized
308      */
309     public static void serializeNlri(final UnkeyedListEntryNode linkstate, final ByteBuf buffer) {
310         final ByteBuf nlriByteBuf = Unpooled.buffer();
311
312         // serialize common parts
313         final Optional<DataContainerChild<? extends PathArgument, ?>> distinguisher = linkstate.getChild(DISTINGUISHER_NID);
314         if (distinguisher.isPresent()) {
315             nlriByteBuf.writeBytes(((String)distinguisher.get().getValue()).getBytes());
316         }
317         final Optional<DataContainerChild<? extends PathArgument, ?>> protocolId = linkstate.getChild(PROTOCOL_ID_NID);
318         // DOM representation contains values as are in the model, not as are in generated enum
319         nlriByteBuf.writeLong(domProtocolIdValue((String) protocolId.get().getValue()));
320         final Optional<DataContainerChild<? extends PathArgument, ?>> identifier = linkstate.getChild(IDENTIFIER_NID);
321         nlriByteBuf.writeLong(((BigInteger)identifier.get().getValue()).longValue());
322
323         // serialize node
324         final ByteBuf ldescs = Unpooled.buffer();
325         NlriType nlriType = null;
326         final ChoiceNode objectType = (ChoiceNode) linkstate.getChild(OBJECT_TYPE_NID).get();
327         if (objectType.getChild(ADVERTISING_NODE_DESCRIPTORS_NID).isPresent()) {
328
329             // prefix node descriptors
330             NodeNlriParser.serializeNodeDescriptors((ContainerNode)objectType.getChild(ADVERTISING_NODE_DESCRIPTORS_NID).get(), ldescs);
331             TlvUtil.writeTLV(LinkstateNlriParser.LOCAL_NODE_DESCRIPTORS_TYPE, ldescs, nlriByteBuf);
332             final Optional<DataContainerChild<? extends PathArgument, ?>> prefixDescriptors = objectType.getChild(new NodeIdentifier(PrefixDescriptors.QNAME));
333
334             // prefix descriptors
335             if (prefixDescriptors.isPresent()) {
336                 nlriType = PrefixNlriParser.serializePrefixDescriptors((ContainerNode)prefixDescriptors.get(), nlriByteBuf);
337             }
338         } else if (objectType.getChild(LOCAL_NODE_DESCRIPTORS_NID).isPresent()) {
339
340             // link local node descriptors
341             NodeNlriParser.serializeNodeDescriptors((ContainerNode)objectType.getChild(LOCAL_NODE_DESCRIPTORS_NID).get(), ldescs);
342             TlvUtil.writeTLV(LinkstateNlriParser.LOCAL_NODE_DESCRIPTORS_TYPE, ldescs, nlriByteBuf);
343
344             // link remote node descriptors
345             final ByteBuf rdescs = Unpooled.buffer();
346             if (objectType.getChild(REMOTE_NODE_DESCRIPTORS_NID).isPresent()) {
347                 NodeNlriParser.serializeNodeDescriptors((ContainerNode)objectType.getChild(REMOTE_NODE_DESCRIPTORS_NID).get(), rdescs);
348                 TlvUtil.writeTLV(LinkstateNlriParser.REMOTE_NODE_DESCRIPTORS_TYPE, rdescs, nlriByteBuf);
349             }
350
351             // link descriptors
352             final Optional<DataContainerChild<? extends PathArgument, ?>> linkDescriptors = objectType.getChild(new NodeIdentifier(LinkDescriptors.QNAME));
353             if (linkDescriptors.isPresent()) {
354                 LinkNlriParser.serializeLinkDescriptors((ContainerNode)linkDescriptors.get(), nlriByteBuf);
355             }
356             nlriType = NlriType.Link;
357         } else if (objectType.getChild(NODE_DESCRIPTORS_NID).isPresent()) {
358
359             // node descriptors
360             NodeNlriParser.serializeNodeDescriptors((ContainerNode)objectType.getChild(NODE_DESCRIPTORS_NID).get(), ldescs);
361             TlvUtil.writeTLV(LinkstateNlriParser.LOCAL_NODE_DESCRIPTORS_TYPE, ldescs, nlriByteBuf);
362             nlriType = NlriType.Node;
363         } else {
364             LOG.warn("Unknown Object Type.");
365         }
366         TlvUtil.writeTLV(nlriType.getIntValue(), nlriByteBuf, buffer);
367     }
368 }