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