BUG-4692: Migrate TCP-MD5 support in bgp package to netty's native-epoll
[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.annotations.VisibleForTesting;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import io.netty.buffer.ByteBuf;
14 import io.netty.buffer.Unpooled;
15 import java.math.BigInteger;
16 import java.util.ArrayList;
17 import java.util.List;
18 import org.opendaylight.protocol.bgp.linkstate.spi.TlvUtil;
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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.Identifier;
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.ProtocolId;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.RouteDistinguisher;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.ObjectType;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.destination.CLinkstateDestination;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.destination.CLinkstateDestinationBuilder;
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.NodeCaseBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.PrefixCaseBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.link._case.LinkDescriptors;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.link._case.LocalNodeDescriptors;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.link._case.RemoteNodeDescriptors;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.node._case.NodeDescriptors;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.prefix._case.AdvertisingNodeDescriptors;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.prefix._case.PrefixDescriptors;
38 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;
39 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;
40 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;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Attributes;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes1;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlriBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlri;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlriBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutes;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.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
66     private static final Logger LOG = LoggerFactory.getLogger(LinkstateNlriParser.class);
67
68     private static final int ROUTE_DISTINGUISHER_LENGTH = 8;
69     private static final int PROTOCOL_ID_LENGTH = 1;
70     private static final int IDENTIFIER_LENGTH = 8;
71
72     private static final int TYPE_LENGTH = 2;
73     private static final int LENGTH_SIZE = 2;
74
75     private static final int LOCAL_NODE_DESCRIPTORS_TYPE = 256;
76     private static final int REMOTE_NODE_DESCRIPTORS_TYPE = 257;
77
78     @VisibleForTesting
79     public static final NodeIdentifier OBJECT_TYPE_NID = new NodeIdentifier(ObjectType.QNAME);
80     @VisibleForTesting
81     public static final NodeIdentifier NODE_DESCRIPTORS_NID = new NodeIdentifier(NodeDescriptors.QNAME);
82     @VisibleForTesting
83     public static final NodeIdentifier LOCAL_NODE_DESCRIPTORS_NID = new NodeIdentifier(LocalNodeDescriptors.QNAME);
84     @VisibleForTesting
85     public static final NodeIdentifier REMOTE_NODE_DESCRIPTORS_NID = new NodeIdentifier(RemoteNodeDescriptors.QNAME);
86     @VisibleForTesting
87     public static final NodeIdentifier ADVERTISING_NODE_DESCRIPTORS_NID = new NodeIdentifier(AdvertisingNodeDescriptors.QNAME);
88     @VisibleForTesting
89     public static final NodeIdentifier PREFIX_DESCRIPTORS_NID = new NodeIdentifier(PrefixDescriptors.QNAME);
90     @VisibleForTesting
91     public static final NodeIdentifier LINK_DESCRIPTORS_NID = new NodeIdentifier(LinkDescriptors.QNAME);
92
93     @VisibleForTesting
94     public static final NodeIdentifier DISTINGUISHER_NID = new NodeIdentifier(QName.create(CLinkstateDestination.QNAME, "distinguisher").intern());
95     @VisibleForTesting
96     public static final NodeIdentifier PROTOCOL_ID_NID = new NodeIdentifier(QName.create(CLinkstateDestination.QNAME, "protocol-id").intern());
97     @VisibleForTesting
98     public static final NodeIdentifier IDENTIFIER_NID = new NodeIdentifier(QName.create(CLinkstateDestination.QNAME, "identifier").intern());
99
100     private final boolean isVpn;
101
102     public LinkstateNlriParser(final boolean isVpn) {
103         this.isVpn = isVpn;
104     }
105
106
107     /**
108      * Parses common parts for Link State Nodes, Links and Prefixes, that includes protocol ID and identifier tlv.
109      *
110      * @param nlri as byte array
111      * @param isVpn flag which determines that destination has route distinguisher
112      * @return {@link CLinkstateDestination}
113      * @throws BGPParsingException if parsing was unsuccessful
114      */
115     public static List<CLinkstateDestination> parseNlri(final ByteBuf nlri, final boolean isVpn) throws BGPParsingException {
116         final List<CLinkstateDestination> dests = new ArrayList<>();
117         while (nlri.isReadable()) {
118             final CLinkstateDestinationBuilder builder = new CLinkstateDestinationBuilder();
119             final NlriType type = NlriType.forValue(nlri.readUnsignedShort());
120
121             // length means total length of the tlvs including route distinguisher not including the type field
122             final int length = nlri.readUnsignedShort();
123             RouteDistinguisher distinguisher = null;
124             if (isVpn) {
125                 // this parses route distinguisher
126                 distinguisher = new RouteDistinguisher(BigInteger.valueOf(nlri.readLong()));
127                 builder.setDistinguisher(distinguisher);
128             }
129             // parse source protocol
130             final ProtocolId sp = ProtocolId.forValue(nlri.readByte());
131             builder.setProtocolId(sp);
132
133             // parse identifier
134             final Identifier identifier = new Identifier(BigInteger.valueOf(nlri.readLong()));
135             builder.setIdentifier(identifier);
136
137             // if we are dealing with linkstate nodes/links, parse local node descriptor
138             org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.NodeIdentifier localDescriptor = null;
139             ByteBuf rest = null;
140             if (!type.equals(NlriType.Ipv4TeLsp) && !type.equals(NlriType.Ipv6TeLsp)) {
141                 final int localtype = nlri.readUnsignedShort();
142                 final int locallength = nlri.readUnsignedShort();
143                 if (localtype == LOCAL_NODE_DESCRIPTORS_TYPE) {
144                     localDescriptor = NodeNlriParser.parseNodeDescriptors(nlri.readSlice(locallength), type, true);
145                 }
146                 final int restLength = length - (isVpn ? ROUTE_DISTINGUISHER_LENGTH : 0) - PROTOCOL_ID_LENGTH -
147                     IDENTIFIER_LENGTH - TYPE_LENGTH - LENGTH_SIZE - locallength;
148                 LOG.trace("Restlength {}", restLength);
149                 rest = nlri.readSlice(restLength);
150             }
151             builder.setObjectType(SimpleNlriTypeRegistry.getInstance().parseNlriType(nlri, type, localDescriptor, rest));
152             dests.add(builder.build());
153         }
154         return dests;
155     }
156
157     @Override
158     public void parseNlri(final ByteBuf nlri, final MpUnreachNlriBuilder builder) throws BGPParsingException {
159         if (!nlri.isReadable()) {
160             return;
161         }
162         final List<CLinkstateDestination> dst = parseNlri(nlri, this.isVpn);
163
164         builder.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(
165             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(
166                 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(
167                     dst).build()).build()).build());
168     }
169
170     @Override
171     public void parseNlri(final ByteBuf nlri, final MpReachNlriBuilder builder) throws BGPParsingException {
172         if (!nlri.isReadable()) {
173             return;
174         }
175         final List<CLinkstateDestination> dst = parseNlri(nlri, this.isVpn);
176
177         builder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(
178             new DestinationLinkstateCaseBuilder().setDestinationLinkstate(
179                 new DestinationLinkstateBuilder().setCLinkstateDestination(dst).build()).build()).build());
180     }
181
182     /**
183      * Serializes Linkstate NLRI to byte array. We need this as NLRI serves as a key in upper layers.
184      *
185      * @param destination Linkstate NLRI to be serialized
186      * @param buffer where Linkstate NLRI will be serialized
187      */
188     public static void serializeNlri(final CLinkstateDestination destination, final ByteBuf buffer) {
189         final ByteBuf nlriByteBuf = Unpooled.buffer();
190         if (destination.getDistinguisher() != null) {
191             nlriByteBuf.writeBytes(destination.getDistinguisher().getValue().toByteArray());
192         }
193         nlriByteBuf.writeByte(destination.getProtocolId().getIntValue());
194         nlriByteBuf.writeLong(destination.getIdentifier().getValue().longValue());
195         final ByteBuf ldescs = Unpooled.buffer();
196         final NlriType nlriType = SimpleNlriTypeRegistry.getInstance().serializeNlriType(destination, ldescs, nlriByteBuf);
197         Preconditions.checkNotNull(nlriType, "NLRI Type value should not be null.");
198         TlvUtil.writeTLV(nlriType.getIntValue(), nlriByteBuf, buffer);
199     }
200
201     @Override
202     public void serializeAttribute(final DataObject attribute, final ByteBuf byteAggregator) {
203         Preconditions.checkArgument(attribute instanceof Attributes, "Attribute parameter is not a PathAttribute object.");
204         final Attributes pathAttributes = (Attributes) attribute;
205         final Attributes1 pathAttributes1 = pathAttributes.getAugmentation(Attributes1.class);
206         final Attributes2 pathAttributes2 = pathAttributes.getAugmentation(Attributes2.class);
207         if (pathAttributes1 != null) {
208             final AdvertizedRoutes routes = (pathAttributes1.getMpReachNlri()).getAdvertizedRoutes();
209             if (routes != null &&
210                 routes.getDestinationType()
211                 instanceof
212                 org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLinkstateCase) {
213                 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
214                     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();
215
216                 for (final CLinkstateDestination cLinkstateDestination : linkstateCase.getDestinationLinkstate().getCLinkstateDestination()) {
217                     serializeNlri(cLinkstateDestination, byteAggregator);
218                 }
219             }
220         } else if (pathAttributes2 != null) {
221             final MpUnreachNlri mpUnreachNlri = pathAttributes2.getMpUnreachNlri();
222             if (mpUnreachNlri.getWithdrawnRoutes() != null && mpUnreachNlri.getWithdrawnRoutes().getDestinationType() instanceof DestinationLinkstateCase) {
223                 final DestinationLinkstateCase linkstateCase = (DestinationLinkstateCase) mpUnreachNlri.getWithdrawnRoutes().getDestinationType();
224                 for (final CLinkstateDestination cLinkstateDestination : linkstateCase.getDestinationLinkstate().getCLinkstateDestination()) {
225                     serializeNlri(cLinkstateDestination, byteAggregator);
226                 }
227             }
228         }
229     }
230
231     // FIXME : use codec
232     private static int domProtocolIdValue(final String protocolId) {
233         switch (protocolId) {
234         case "isis-level1":
235             return ProtocolId.IsisLevel1.getIntValue();
236         case "isis-level2":
237             return ProtocolId.IsisLevel2.getIntValue();
238         case "ospf":
239             return ProtocolId.Ospf.getIntValue();
240         case "direct":
241             return ProtocolId.Direct.getIntValue();
242         case "static":
243             return ProtocolId.Static.getIntValue();
244         case "ospf-v3":
245             return ProtocolId.OspfV3.getIntValue();
246         case "rsvp-te":
247             return ProtocolId.RsvpTe.getIntValue();
248         case "bgp-epe":
249             return ProtocolId.BgpEpe.getIntValue();
250         case "segment-routing":
251             return ProtocolId.SegmentRouting.getIntValue();
252         default:
253             return 0;
254         }
255     }
256
257     public static CLinkstateDestination extractLinkstateDestination(final DataContainerNode<? extends PathArgument> linkstate) {
258         final CLinkstateDestinationBuilder builder = new CLinkstateDestinationBuilder();
259         serializeCommonParts(builder, linkstate);
260
261         final ChoiceNode objectType = (ChoiceNode) linkstate.getChild(OBJECT_TYPE_NID).get();
262         if (objectType.getChild(ADVERTISING_NODE_DESCRIPTORS_NID).isPresent()) {
263             serializeAdvertisedNodeDescriptor(builder, objectType);
264         } else if (objectType.getChild(LOCAL_NODE_DESCRIPTORS_NID).isPresent()) {
265             serializeLocalNodeDescriptor(builder, objectType);
266         } else if (objectType.getChild(NODE_DESCRIPTORS_NID).isPresent()) {
267             serializeNodeDescriptor(builder, objectType);
268         } else if (TeLspNlriSerializer.isTeLsp(objectType)) {
269             builder.setObjectType(TeLspNlriSerializer.serializeTeLsp(objectType));
270         } else {
271             LOG.warn("Unknown Object Type: {}.", objectType);
272         }
273         return builder.build();
274     }
275
276     private static void serializeNodeDescriptor(final CLinkstateDestinationBuilder builder, final ChoiceNode objectType) {
277         final NodeCaseBuilder nodeBuilder = new NodeCaseBuilder();
278         // node descriptors
279         nodeBuilder.setNodeDescriptors(NodeNlriParser.serializeNodeDescriptors((ContainerNode) objectType.getChild(NODE_DESCRIPTORS_NID).get()));
280         builder.setObjectType(nodeBuilder.build());
281     }
282
283     private static void serializeLocalNodeDescriptor(final CLinkstateDestinationBuilder builder, final ChoiceNode objectType) {
284         // link local node descriptors
285         final LinkCaseBuilder linkBuilder = new LinkCaseBuilder();
286
287         linkBuilder.setLocalNodeDescriptors(NodeNlriParser.serializeLocalNodeDescriptors((ContainerNode) objectType.getChild(LOCAL_NODE_DESCRIPTORS_NID).get()));
288         // link remote node descriptors
289         if (objectType.getChild(REMOTE_NODE_DESCRIPTORS_NID).isPresent()) {
290             linkBuilder.setRemoteNodeDescriptors(NodeNlriParser.serializeRemoteNodeDescriptors((ContainerNode) objectType.getChild(REMOTE_NODE_DESCRIPTORS_NID).get()));
291         }
292         // link descriptors
293         final Optional<DataContainerChild<? extends PathArgument, ?>> linkDescriptors = objectType.getChild(LINK_DESCRIPTORS_NID);
294         if (linkDescriptors.isPresent()) {
295             linkBuilder.setLinkDescriptors(LinkNlriParser.serializeLinkDescriptors((ContainerNode) linkDescriptors.get()));
296         }
297         builder.setObjectType(linkBuilder.build());
298     }
299
300     private static void serializeAdvertisedNodeDescriptor(final CLinkstateDestinationBuilder builder, final ChoiceNode objectType) {
301         // prefix node descriptors
302         final PrefixCaseBuilder prefixBuilder = new PrefixCaseBuilder();
303         prefixBuilder.setAdvertisingNodeDescriptors(NodeNlriParser.serializeAdvNodeDescriptors((ContainerNode) objectType.getChild(
304             ADVERTISING_NODE_DESCRIPTORS_NID).get()));
305
306         // prefix descriptors
307         final Optional<DataContainerChild<? extends PathArgument, ?>> prefixDescriptors = objectType.getChild(PREFIX_DESCRIPTORS_NID);
308         if (prefixDescriptors.isPresent()) {
309             prefixBuilder.setPrefixDescriptors(PrefixNlriSerializer.serializePrefixDescriptors((ContainerNode) prefixDescriptors.get()));
310         }
311         builder.setObjectType(prefixBuilder.build());
312     }
313
314     private static void serializeCommonParts(final CLinkstateDestinationBuilder builder, final DataContainerNode<? extends PathArgument> linkstate) {
315         // serialize common parts
316         final Optional<DataContainerChild<? extends PathArgument, ?>> distinguisher = linkstate.getChild(DISTINGUISHER_NID);
317         if (distinguisher.isPresent()) {
318             builder.setDistinguisher(new RouteDistinguisher((BigInteger) distinguisher.get().getValue()));
319         }
320         final Optional<DataContainerChild<? extends PathArgument, ?>> protocolId = linkstate.getChild(PROTOCOL_ID_NID);
321         // DOM representation contains values as are in the model, not as are in generated enum
322         if (protocolId.isPresent()) {
323             builder.setProtocolId(ProtocolId.forValue(domProtocolIdValue((String) protocolId.get().getValue())));
324         }
325         final Optional<DataContainerChild<? extends PathArgument, ?>> identifier = linkstate.getChild(IDENTIFIER_NID);
326         if (identifier.isPresent()) {
327             builder.setIdentifier(new Identifier((BigInteger) identifier.get().getValue()));
328         }
329     }
330 }