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