BUG-2383 : DOM Linkstate NLRI serializer
[bgpcep.git] / bgp / linkstate / src / main / java / org / opendaylight / protocol / bgp / linkstate / nlri / NodeNlriParser.java
1 /*
2  * Copyright (c) 2014 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.annotations.VisibleForTesting;
11 import com.google.common.base.Optional;
12 import com.google.common.primitives.UnsignedInteger;
13 import io.netty.buffer.ByteBuf;
14 import io.netty.buffer.ByteBufUtil;
15 import io.netty.buffer.Unpooled;
16 import org.opendaylight.protocol.bgp.linkstate.spi.TlvUtil;
17 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
18 import org.opendaylight.protocol.util.ByteArray;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.AreaIdentifier;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.DomainIdentifier;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.IsisRouterIdentifier;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.NlriType;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.OspfInterfaceIdentifier;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.isis.lan.identifier.IsIsRouterIdentifier;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.isis.lan.identifier.IsIsRouterIdentifierBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.link._case.LocalNodeDescriptorsBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.link._case.RemoteNodeDescriptorsBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.node._case.NodeDescriptors;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.node._case.NodeDescriptorsBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.prefix._case.AdvertisingNodeDescriptorsBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.CRouterIdentifier;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.IsisNodeCase;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.IsisNodeCaseBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.IsisPseudonodeCase;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.IsisPseudonodeCaseBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.OspfNodeCase;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.OspfNodeCaseBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.OspfPseudonodeCase;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.OspfPseudonodeCaseBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.isis.node._case.IsisNode;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.isis.node._case.IsisNodeBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.isis.pseudonode._case.IsisPseudonode;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.isis.pseudonode._case.IsisPseudonodeBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.ospf.node._case.OspfNode;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.ospf.node._case.OspfNodeBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.ospf.pseudonode._case.OspfPseudonode;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.node.identifier.c.router.identifier.ospf.pseudonode._case.OspfPseudonodeBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.IsoSystemIdentifier;
50 import org.opendaylight.yangtools.yang.common.QName;
51 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
52 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
53 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
54 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
55 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 @VisibleForTesting
60 public final class NodeNlriParser {
61
62     private static final Logger LOG = LoggerFactory.getLogger(NodeNlriParser.class);
63
64     private NodeNlriParser() {
65         throw new UnsupportedOperationException();
66     }
67
68     private static final int OSPF_PSEUDONODE_ROUTER_ID_LENGTH = 8;
69     private static final int OSPF_ROUTER_ID_LENGTH = 4;
70     private static final int ISO_SYSTEM_ID_LENGTH = 6;
71     private static final int PSN_LENGTH = 1;
72
73     /* Node Descriptor TLVs */
74     private static final int AS_NUMBER = 512;
75     private static final int BGP_LS_ID = 513;
76     private static final int AREA_ID = 514;
77     private static final int IGP_ROUTER_ID = 515;
78
79     /* Node Descriptor QNames */
80     private static final NodeIdentifier AS_NUMBER_NID = new NodeIdentifier(QName.cachedReference(QName.create(NodeDescriptors.QNAME, "as-number")));
81     private static final NodeIdentifier AREA_NID = new NodeIdentifier(QName.cachedReference(QName.create(NodeDescriptors.QNAME, "area-id")));
82     private static final NodeIdentifier DOMAIN_NID = new NodeIdentifier(QName.cachedReference(QName.create(NodeDescriptors.QNAME, "domain-id")));
83     private static final NodeIdentifier ROUTER_NID = new NodeIdentifier(CRouterIdentifier.QNAME);
84
85     /* Router Identifier QNames */
86     private static final NodeIdentifier ISIS_NODE_NID = new NodeIdentifier(IsisNode.QNAME);
87     private static final NodeIdentifier ISIS_PSEUDONODE_NID = new NodeIdentifier(IsisPseudonode.QNAME);
88     private static final NodeIdentifier OSPF_NODE_NID = new NodeIdentifier(OspfNode.QNAME);
89     private static final NodeIdentifier OSPF_PSEUDONODE_NID = new NodeIdentifier(OspfPseudonode.QNAME);
90     private static final NodeIdentifier ISIS_ROUTER_NID = new NodeIdentifier(IsisRouterIdentifier.QNAME);
91     private static final NodeIdentifier ISO_SYSTEM_NID = new NodeIdentifier(QName.cachedReference(QName.create(NodeDescriptors.QNAME, "iso-system-id")));
92     private static final NodeIdentifier PSN_NID = new NodeIdentifier(QName.cachedReference(QName.create(NodeDescriptors.QNAME, "psn")));
93     private static final NodeIdentifier OSPF_ROUTER_NID = new NodeIdentifier(QName.cachedReference(QName.create(NodeDescriptors.QNAME, "ospf-router-id")));
94     private static final NodeIdentifier LAN_IFACE_NID = new NodeIdentifier(QName.cachedReference(QName.create(NodeDescriptors.QNAME, "lan-interface")));
95
96     static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.NodeIdentifier parseNodeDescriptors(final ByteBuf buffer, final NlriType nlriType, final boolean local) throws BGPParsingException {
97         AsNumber asnumber = null;
98         DomainIdentifier bgpId = null;
99         AreaIdentifier ai = null;
100         CRouterIdentifier routerId = null;
101         while (buffer.isReadable()) {
102             final int type = buffer.readUnsignedShort();
103             final int length = buffer.readUnsignedShort();
104             final ByteBuf value = buffer.readSlice(length);
105             if (LOG.isTraceEnabled()) {
106                 LOG.trace("Parsing Node Descriptor: {}", ByteBufUtil.hexDump(value));
107             }
108             switch (type) {
109             case AS_NUMBER:
110                 asnumber = new AsNumber(value.readUnsignedInt());
111                 LOG.debug("Parsed {}", asnumber);
112                 break;
113             case BGP_LS_ID:
114                 bgpId = new DomainIdentifier(value.readUnsignedInt());
115                 LOG.debug("Parsed {}", bgpId);
116                 break;
117             case AREA_ID:
118                 ai = new AreaIdentifier(value.readUnsignedInt());
119                 LOG.debug("Parsed area identifier {}", ai);
120                 break;
121             case IGP_ROUTER_ID:
122                 routerId = parseRouterId(value);
123                 LOG.debug("Parsed Router Identifier {}", routerId);
124                 break;
125             default:
126                 throw new BGPParsingException("Node Descriptor not recognized, type: " + type);
127             }
128         }
129         LOG.trace("Finished parsing Node descriptors.");
130         switch (nlriType) {
131         case Link:
132             if (local) {
133                 return new LocalNodeDescriptorsBuilder().setAsNumber(asnumber).setAreaId(ai).setCRouterIdentifier(routerId).setDomainId(bgpId).build();
134             } else {
135                 return new RemoteNodeDescriptorsBuilder().setAsNumber(asnumber).setAreaId(ai).setCRouterIdentifier(routerId).setDomainId(bgpId).build();
136             }
137         case Node:
138             return new NodeDescriptorsBuilder().setAsNumber(asnumber).setAreaId(ai).setCRouterIdentifier(routerId).setDomainId(bgpId).build();
139         case Ipv4Prefix:
140         case Ipv6Prefix:
141             return new AdvertisingNodeDescriptorsBuilder().setAsNumber(asnumber).setAreaId(ai).setCRouterIdentifier(routerId).setDomainId(bgpId).build();
142         default:
143             throw new IllegalStateException("NLRI type not recognized.");
144         }
145     }
146
147     private static CRouterIdentifier parseRouterId(final ByteBuf value) throws BGPParsingException {
148         if (value.readableBytes() == ISO_SYSTEM_ID_LENGTH || (value.readableBytes() == ISO_SYSTEM_ID_LENGTH + PSN_LENGTH && value.getByte(ISO_SYSTEM_ID_LENGTH) == 0)) {
149             return new IsisNodeCaseBuilder().setIsisNode(
150                 new IsisNodeBuilder().setIsoSystemId(new IsoSystemIdentifier(ByteArray.readBytes(value, ISO_SYSTEM_ID_LENGTH))).build()).build();
151         }
152         if (value.readableBytes() == ISO_SYSTEM_ID_LENGTH + PSN_LENGTH) {
153             final IsIsRouterIdentifier iri = new IsIsRouterIdentifierBuilder().setIsoSystemId(
154                 new IsoSystemIdentifier(ByteArray.readBytes(value, ISO_SYSTEM_ID_LENGTH))).build();
155             return new IsisPseudonodeCaseBuilder().setIsisPseudonode(new IsisPseudonodeBuilder().setIsIsRouterIdentifier(iri).setPsn((short) value.readByte()).build()).build();
156         }
157         if (value.readableBytes() == OSPF_ROUTER_ID_LENGTH) {
158             return new OspfNodeCaseBuilder().setOspfNode(
159                 new OspfNodeBuilder().setOspfRouterId(value.readUnsignedInt()).build()).build();
160         }
161         if (value.readableBytes() == OSPF_PSEUDONODE_ROUTER_ID_LENGTH) {
162             return new OspfPseudonodeCaseBuilder().setOspfPseudonode(
163                 new OspfPseudonodeBuilder().setOspfRouterId(value.readUnsignedInt()).setLanInterface(new OspfInterfaceIdentifier(value.readUnsignedInt())).build()).build();
164         }
165         throw new BGPParsingException("Router Id of invalid length " + value.readableBytes());
166     }
167
168     static void serializeNodeDescriptors(final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.NodeIdentifier descriptors, final ByteBuf buffer) {
169         if (descriptors.getAsNumber() != null) {
170             TlvUtil.writeTLV(AS_NUMBER, Unpooled.copyInt(UnsignedInteger.valueOf(descriptors.getAsNumber().getValue()).intValue()), buffer);
171         }
172         if (descriptors.getDomainId() != null) {
173             TlvUtil.writeTLV(BGP_LS_ID, Unpooled.copyInt(UnsignedInteger.valueOf(descriptors.getDomainId().getValue()).intValue()), buffer);
174         }
175         if (descriptors.getAreaId() != null) {
176             TlvUtil.writeTLV(AREA_ID, Unpooled.copyInt(UnsignedInteger.valueOf(descriptors.getAreaId().getValue()).intValue()), buffer);
177         }
178         if (descriptors.getCRouterIdentifier() != null) {
179             final ByteBuf routerIdBuf = Unpooled.buffer();
180             serializeRouterId(descriptors.getCRouterIdentifier(), routerIdBuf);
181             TlvUtil.writeTLV(IGP_ROUTER_ID, routerIdBuf, buffer);
182         }
183     }
184
185     private static void serializeRouterId(final CRouterIdentifier routerId, final ByteBuf buffer) {
186         if (routerId instanceof IsisNodeCase) {
187             final IsisNode isis = ((IsisNodeCase) routerId).getIsisNode();
188             buffer.writeBytes(isis.getIsoSystemId().getValue());
189         } else if (routerId instanceof IsisPseudonodeCase) {
190             final IsisPseudonode isis = ((IsisPseudonodeCase) routerId).getIsisPseudonode();
191             buffer.writeBytes(isis.getIsIsRouterIdentifier().getIsoSystemId().getValue());
192             buffer.writeByte(((isis.getPsn() != null) ? isis.getPsn() : 0));
193         } else if (routerId instanceof OspfNodeCase) {
194             buffer.writeInt(UnsignedInteger.valueOf(((OspfNodeCase) routerId).getOspfNode().getOspfRouterId()).intValue());
195         } else if (routerId instanceof OspfPseudonodeCase) {
196             final OspfPseudonode node = ((OspfPseudonodeCase) routerId).getOspfPseudonode();
197             buffer.writeInt(UnsignedInteger.valueOf(node.getOspfRouterId()).intValue());
198             buffer.writeInt(UnsignedInteger.valueOf(node.getLanInterface().getValue()).intValue());
199         }
200     }
201
202     private static void serializeIsisNode(final ContainerNode isis, final ByteBuf buffer) {
203         buffer.writeBytes((byte[])isis.getChild(ISO_SYSTEM_NID).get().getValue());
204     }
205
206     private static void serializeOspfNode(final ContainerNode ospf, final ByteBuf buffer) {
207         buffer.writeInt(UnsignedInteger.valueOf((Long)ospf.getChild(OSPF_ROUTER_NID).get().getValue()).intValue());
208     }
209
210     private static void serializeRouterId(final ChoiceNode routerId, final ByteBuf buffer) {
211         if (routerId.getChild(ISIS_NODE_NID).isPresent()) {
212             serializeIsisNode((ContainerNode)routerId.getChild(ISIS_NODE_NID).get(), buffer);
213         } else if (routerId.getChild(ISIS_PSEUDONODE_NID).isPresent()) {
214             final ContainerNode isisPseudo = (ContainerNode)routerId.getChild(ISIS_PSEUDONODE_NID).get();
215             serializeIsisNode((ContainerNode) isisPseudo.getChild(ISIS_ROUTER_NID).get(), buffer);
216             if (isisPseudo.getChild(PSN_NID).isPresent()) {
217                 buffer.writeByte(((Short)isisPseudo.getChild(PSN_NID).get().getValue()));
218             } else {
219                 buffer.writeZero(PSN_LENGTH);
220             }
221         } else if (routerId.getChild(OSPF_NODE_NID).isPresent()) {
222             serializeOspfNode((ContainerNode)routerId.getChild(OSPF_NODE_NID).get(), buffer);
223         } else if (routerId.getChild(OSPF_PSEUDONODE_NID).isPresent()) {
224             final ContainerNode ospfPseudo = (ContainerNode)routerId.getChild(OSPF_PSEUDONODE_NID).get();
225             serializeOspfNode((ContainerNode)ospfPseudo.getChild(OSPF_NODE_NID), buffer);
226             buffer.writeInt(UnsignedInteger.valueOf((Long)ospfPseudo.getChild(LAN_IFACE_NID).get().getValue()).intValue());
227         }
228     }
229
230     static void serializeNodeDescriptors(final ContainerNode descriptors, final ByteBuf buffer) {
231         final Optional<DataContainerChild<? extends PathArgument, ?>> asNumber = descriptors.getChild(AS_NUMBER_NID);
232         if (asNumber.isPresent()) {
233             TlvUtil.writeTLV(AS_NUMBER, Unpooled.copyInt(UnsignedInteger.valueOf((Long)asNumber.get().getValue()).intValue()), buffer);
234         }
235         final Optional<DataContainerChild<? extends PathArgument, ?>> domainId = descriptors.getChild(DOMAIN_NID);
236         if (domainId.isPresent()) {
237             TlvUtil.writeTLV(BGP_LS_ID, Unpooled.copyInt(UnsignedInteger.valueOf((Long)domainId.get().getValue()).intValue()), buffer);
238         }
239         final Optional<DataContainerChild<? extends PathArgument, ?>> areaId = descriptors.getChild(AREA_NID);
240         if (areaId.isPresent()) {
241             TlvUtil.writeTLV(AREA_ID, Unpooled.copyInt(UnsignedInteger.valueOf((Long)domainId.get().getValue()).intValue()), buffer);
242         }
243         final Optional<DataContainerChild<? extends PathArgument, ?>> routerId = descriptors.getChild(ROUTER_NID);
244         if (routerId.isPresent()) {
245             final ByteBuf routerIdBuf = Unpooled.buffer();
246             serializeRouterId((ChoiceNode)routerId.get(), routerIdBuf);
247             TlvUtil.writeTLV(IGP_ROUTER_ID, routerIdBuf, buffer);
248         }
249     }
250 }