Code clean up
[bgpcep.git] / bgp / linkstate / src / main / java / org / opendaylight / protocol / bgp / linkstate / impl / 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.impl.nlri;
9
10 import com.google.common.annotations.VisibleForTesting;
11 import com.google.common.base.Preconditions;
12 import io.netty.buffer.ByteBuf;
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.Optional;
17 import org.opendaylight.bgp.concepts.RouteDistinguisherUtil;
18 import org.opendaylight.protocol.bgp.linkstate.spi.AbstractTeLspNlriCodec;
19 import org.opendaylight.protocol.bgp.linkstate.spi.pojo.SimpleNlriTypeRegistry;
20 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
21 import org.opendaylight.protocol.bgp.parser.spi.NlriParser;
22 import org.opendaylight.protocol.bgp.parser.spi.NlriSerializer;
23 import org.opendaylight.protocol.bgp.parser.spi.PeerSpecificParserConstraint;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.Identifier;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.ProtocolId;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.ObjectType;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.destination.CLinkstateDestination;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.destination.CLinkstateDestinationBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.object.type.LinkCaseBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.object.type.NodeCaseBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.object.type.PrefixCaseBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.object.type.link._case.LinkDescriptors;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.object.type.link._case.LocalNodeDescriptors;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.object.type.link._case.RemoteNodeDescriptors;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.object.type.node._case.NodeDescriptors;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.object.type.prefix._case.AdvertisingNodeDescriptors;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.object.type.prefix._case.PrefixDescriptors;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLinkstateCaseBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.update.attributes.mp.reach.nlri.advertized.routes.destination.type.destination.linkstate._case.DestinationLinkstateBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationLinkstateCase;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.Attributes;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.Attributes1;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.Attributes2;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpReachNlriBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpUnreachNlriBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.reach.nlri.AdvertizedRoutes;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.unreach.nlri.WithdrawnRoutes;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
50 import org.opendaylight.yangtools.yang.binding.DataObject;
51 import org.opendaylight.yangtools.yang.common.QName;
52 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
53 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
54 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
55 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
56 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
57 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60
61 /**
62  * Parser and serializer for Linkstate NLRI.
63  */
64 public final class LinkstateNlriParser implements NlriParser, NlriSerializer {
65     private static final Logger LOG = LoggerFactory.getLogger(LinkstateNlriParser.class);
66
67     @VisibleForTesting
68     public static final NodeIdentifier OBJECT_TYPE_NID = new NodeIdentifier(ObjectType.QNAME);
69     @VisibleForTesting
70     public static final NodeIdentifier NODE_DESCRIPTORS_NID = new NodeIdentifier(NodeDescriptors.QNAME);
71     @VisibleForTesting
72     public static final NodeIdentifier LOCAL_NODE_DESCRIPTORS_NID = new NodeIdentifier(LocalNodeDescriptors.QNAME);
73     @VisibleForTesting
74     public static final NodeIdentifier REMOTE_NODE_DESCRIPTORS_NID = new NodeIdentifier(RemoteNodeDescriptors.QNAME);
75     @VisibleForTesting
76     public static final NodeIdentifier ADVERTISING_NODE_DESCRIPTORS_NID
77             = new NodeIdentifier(AdvertisingNodeDescriptors.QNAME);
78     @VisibleForTesting
79     public static final NodeIdentifier PREFIX_DESCRIPTORS_NID = new NodeIdentifier(PrefixDescriptors.QNAME);
80     @VisibleForTesting
81     public static final NodeIdentifier LINK_DESCRIPTORS_NID = new NodeIdentifier(LinkDescriptors.QNAME);
82     @VisibleForTesting
83     public static final NodeIdentifier PROTOCOL_ID_NID = new NodeIdentifier(
84             QName.create(CLinkstateDestination.QNAME.getModule(), "protocol-id"));
85     @VisibleForTesting
86     public static final NodeIdentifier IDENTIFIER_NID = new NodeIdentifier(
87             QName.create(CLinkstateDestination.QNAME.getModule(), "identifier"));
88     @VisibleForTesting
89     private static final NodeIdentifier DISTINGUISHER_NID = new NodeIdentifier(
90             QName.create(CLinkstateDestination.QNAME.getModule(), "route-distinguisher"));
91     private final SimpleNlriTypeRegistry nlriTypeReg = SimpleNlriTypeRegistry.getInstance();
92
93
94     /**
95      * Parses common parts for Link State Nodes, Links and Prefixes, that includes protocol ID and identifier tlv.
96      *
97      * @param nlri as byte array
98      * @return {@link CLinkstateDestination}
99      */
100     private List<CLinkstateDestination> parseNlri(final ByteBuf nlri) {
101         final List<CLinkstateDestination> dests = new ArrayList<>();
102         while (nlri.isReadable()) {
103             final CLinkstateDestination destination = this.nlriTypeReg.parseNlriType(nlri);
104             if (destination == null) {
105                 continue;
106             }
107             dests.add(destination);
108         }
109         return dests;
110     }
111
112     @Override
113     public void parseNlri(final ByteBuf nlri, final MpUnreachNlriBuilder builder,
114             final PeerSpecificParserConstraint constraint) throws BGPParsingException {
115         if (!nlri.isReadable()) {
116             return;
117         }
118         final List<CLinkstateDestination> dst = parseNlri(nlri);
119
120         builder.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(
121                 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.update
122                         .attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationLinkstateCaseBuilder()
123                         .setDestinationLinkstate(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang
124                                 .bgp.linkstate.rev180329.update.attributes.mp.unreach.nlri.withdrawn.routes.destination
125                                 .type.destination.linkstate._case.DestinationLinkstateBuilder()
126                                 .setCLinkstateDestination(dst).build()).build()).build());
127     }
128
129     @Override
130     public void parseNlri(final ByteBuf nlri, final MpReachNlriBuilder builder,
131             final PeerSpecificParserConstraint constraint) throws BGPParsingException {
132         if (!nlri.isReadable()) {
133             return;
134         }
135         final List<CLinkstateDestination> dst = parseNlri(nlri);
136
137         builder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(
138             new DestinationLinkstateCaseBuilder().setDestinationLinkstate(
139                 new DestinationLinkstateBuilder().setCLinkstateDestination(dst).build()).build()).build());
140     }
141
142     @Override
143     public void serializeAttribute(final DataObject attribute, final ByteBuf byteAggregator) {
144         Preconditions.checkArgument(attribute instanceof Attributes,
145                 "Attribute parameter is not a PathAttribute object.");
146         final Attributes pathAttributes = (Attributes) attribute;
147         final Attributes1 pathAttributes1 = pathAttributes.getAugmentation(Attributes1.class);
148         final Attributes2 pathAttributes2 = pathAttributes.getAugmentation(Attributes2.class);
149         if (pathAttributes1 != null) {
150             serializeAdvertisedRoutes(pathAttributes1.getMpReachNlri().getAdvertizedRoutes(), byteAggregator);
151         } else if (pathAttributes2 != null) {
152             serializeWithDrawnRoutes(pathAttributes2.getMpUnreachNlri().getWithdrawnRoutes(), byteAggregator);
153         }
154     }
155
156     private void serializeWithDrawnRoutes(final WithdrawnRoutes withdrawnRoutes, final ByteBuf byteAggregator) {
157         if (withdrawnRoutes != null && withdrawnRoutes.getDestinationType() instanceof DestinationLinkstateCase) {
158             final DestinationLinkstateCase linkstateCase
159                     = (DestinationLinkstateCase) withdrawnRoutes.getDestinationType();
160             for (final CLinkstateDestination cLinkstateDestination : linkstateCase.getDestinationLinkstate()
161                     .getCLinkstateDestination()) {
162                 this.nlriTypeReg.serializeNlriType(cLinkstateDestination, byteAggregator);
163             }
164         }
165     }
166
167     private void serializeAdvertisedRoutes(final AdvertizedRoutes advertizedRoutes, final ByteBuf byteAggregator) {
168         if (advertizedRoutes != null && advertizedRoutes.getDestinationType()
169                 instanceof
170                 org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.update
171                         .attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLinkstateCase) {
172             final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.update
173                     .attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLinkstateCase
174                     linkstateCase = (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate
175                     .rev180329.update.attributes.mp.reach.nlri.advertized.routes.destination.type
176                     .DestinationLinkstateCase) advertizedRoutes.getDestinationType();
177
178             for (final CLinkstateDestination cLinkstateDestination : linkstateCase.getDestinationLinkstate()
179                     .getCLinkstateDestination()) {
180                 this.nlriTypeReg.serializeNlriType(cLinkstateDestination, byteAggregator);
181             }
182         }
183     }
184
185     // FIXME : use codec
186     private static int domProtocolIdValue(final String protocolId) {
187         switch (protocolId) {
188         case "isis-level1":
189             return ProtocolId.IsisLevel1.getIntValue();
190         case "isis-level2":
191             return ProtocolId.IsisLevel2.getIntValue();
192         case "ospf":
193             return ProtocolId.Ospf.getIntValue();
194         case "direct":
195             return ProtocolId.Direct.getIntValue();
196         case "static":
197             return ProtocolId.Static.getIntValue();
198         case "ospf-v3":
199             return ProtocolId.OspfV3.getIntValue();
200         case "rsvp-te":
201             return ProtocolId.RsvpTe.getIntValue();
202         case "bgp-epe":
203             return ProtocolId.BgpEpe.getIntValue();
204         case "segment-routing":
205             return ProtocolId.SegmentRouting.getIntValue();
206         default:
207             return 0;
208         }
209     }
210
211     public static CLinkstateDestination extractLinkstateDestination(
212             final DataContainerNode<? extends PathArgument> linkstate) {
213         final CLinkstateDestinationBuilder builder = new CLinkstateDestinationBuilder();
214         serializeCommonParts(builder, linkstate);
215
216         final ChoiceNode objectType = (ChoiceNode) linkstate.getChild(OBJECT_TYPE_NID).get();
217         if (objectType.getChild(ADVERTISING_NODE_DESCRIPTORS_NID).isPresent()) {
218             serializeAdvertisedNodeDescriptor(builder, objectType);
219         } else if (objectType.getChild(LOCAL_NODE_DESCRIPTORS_NID).isPresent()) {
220             serializeLocalNodeDescriptor(builder, objectType);
221         } else if (objectType.getChild(NODE_DESCRIPTORS_NID).isPresent()) {
222             serializeNodeDescriptor(builder, objectType);
223         } else if (AbstractTeLspNlriCodec.isTeLsp(objectType)) {
224             builder.setObjectType(AbstractTeLspNlriCodec.serializeTeLsp(objectType));
225         } else {
226             LOG.warn("Unknown Object Type: {}.", objectType);
227         }
228         return builder.build();
229     }
230
231     private static void serializeNodeDescriptor(final CLinkstateDestinationBuilder builder,
232             final ChoiceNode objectType) {
233         final NodeCaseBuilder nodeBuilder = new NodeCaseBuilder();
234         // node descriptors
235         nodeBuilder.setNodeDescriptors(NodeNlriParser
236                 .serializeNodeDescriptors((ContainerNode) objectType.getChild(NODE_DESCRIPTORS_NID).get()));
237         builder.setObjectType(nodeBuilder.build());
238     }
239
240     private static void serializeLocalNodeDescriptor(final CLinkstateDestinationBuilder builder,
241             final ChoiceNode objectType) {
242         // link local node descriptors
243         final LinkCaseBuilder linkBuilder = new LinkCaseBuilder();
244
245         linkBuilder.setLocalNodeDescriptors(NodeNlriParser.serializeLocalNodeDescriptors((ContainerNode) objectType
246                 .getChild(LOCAL_NODE_DESCRIPTORS_NID).get()));
247         // link remote node descriptors
248         if (objectType.getChild(REMOTE_NODE_DESCRIPTORS_NID).isPresent()) {
249             linkBuilder.setRemoteNodeDescriptors(NodeNlriParser
250                     .serializeRemoteNodeDescriptors((ContainerNode) objectType.getChild(REMOTE_NODE_DESCRIPTORS_NID)
251                             .get()));
252         }
253         // link descriptors
254         final Optional<DataContainerChild<? extends PathArgument, ?>> linkDescriptors
255                 = objectType.getChild(LINK_DESCRIPTORS_NID);
256         linkDescriptors.ifPresent(dataContainerChild -> linkBuilder.setLinkDescriptors(LinkNlriParser
257                 .serializeLinkDescriptors((ContainerNode) dataContainerChild)));
258         builder.setObjectType(linkBuilder.build());
259     }
260
261     private static void serializeAdvertisedNodeDescriptor(final CLinkstateDestinationBuilder builder,
262             final ChoiceNode objectType) {
263         // prefix node descriptors
264         final PrefixCaseBuilder prefixBuilder = new PrefixCaseBuilder();
265         prefixBuilder.setAdvertisingNodeDescriptors(NodeNlriParser
266                 .serializeAdvNodeDescriptors((ContainerNode) objectType.getChild(ADVERTISING_NODE_DESCRIPTORS_NID)
267                         .get()));
268
269         // prefix descriptors
270         final Optional<DataContainerChild<? extends PathArgument, ?>> prefixDescriptors
271                 = objectType.getChild(PREFIX_DESCRIPTORS_NID);
272         prefixDescriptors.ifPresent(dataContainerChild -> prefixBuilder.setPrefixDescriptors(AbstractPrefixNlriParser
273                 .serializePrefixDescriptors((ContainerNode) dataContainerChild)));
274         builder.setObjectType(prefixBuilder.build());
275     }
276
277     private static void serializeCommonParts(final CLinkstateDestinationBuilder builder,
278             final DataContainerNode<? extends PathArgument> linkstate) {
279         // serialize common parts
280         final Optional<DataContainerChild<? extends PathArgument, ?>> distinguisher
281                 = linkstate.getChild(DISTINGUISHER_NID);
282         distinguisher.ifPresent(dataContainerChild -> builder.setRouteDistinguisher(RouteDistinguisherUtil
283                 .parseRouteDistinguisher(dataContainerChild.getValue())));
284         final Optional<DataContainerChild<? extends PathArgument, ?>> protocolId = linkstate.getChild(PROTOCOL_ID_NID);
285         // DOM representation contains values as are in the model, not as are in generated enum
286         protocolId.ifPresent(dataContainerChild -> builder.setProtocolId(ProtocolId
287                 .forValue(domProtocolIdValue((String) dataContainerChild.getValue()))));
288         final Optional<DataContainerChild<? extends PathArgument, ?>> identifier = linkstate.getChild(IDENTIFIER_NID);
289         identifier.ifPresent(dataContainerChild -> builder
290                 .setIdentifier(new Identifier((BigInteger) dataContainerChild.getValue())));
291     }
292 }