Merge "BUG-2571 : flowspec-routes model"
[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.base.Preconditions;
11 import io.netty.buffer.ByteBuf;
12 import io.netty.buffer.Unpooled;
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.List;
16 import org.opendaylight.protocol.bgp.linkstate.spi.TlvUtil;
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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.Identifier;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.NlriType;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.NodeIdentifier;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.ProtocolId;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.RouteDistinguisher;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.ObjectType;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.destination.CLinkstateDestination;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.destination.CLinkstateDestinationBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.LinkCase;
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.NodeCase;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.NodeCaseBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.PrefixCase;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.PrefixCaseBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.link._case.LocalNodeDescriptors;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.link._case.RemoteNodeDescriptors;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.node._case.NodeDescriptors;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.prefix._case.AdvertisingNodeDescriptors;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.update.path.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.path.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.path.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.update.PathAttributes;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes1;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes2;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlriBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlri;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlriBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.reach.nlri.AdvertizedRoutes;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
50 import org.opendaylight.yangtools.yang.binding.DataObject;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 /**
55  * Parser and serializer for Linkstate NLRI.
56  */
57 public final class LinkstateNlriParser implements NlriParser, NlriSerializer {
58     private static final Logger LOG = LoggerFactory.getLogger(LinkstateNlriParser.class);
59     private static final int ROUTE_DISTINGUISHER_LENGTH = 8;
60     private static final int PROTOCOL_ID_LENGTH = 1;
61     private static final int IDENTIFIER_LENGTH = 8;
62
63     private static final int TYPE_LENGTH = 2;
64     private static final int LENGTH_SIZE = 2;
65
66
67     private static final int LOCAL_NODE_DESCRIPTORS = 256;
68     private static final int REMOTE_NODE_DESCRIPTORS = 257;
69
70     private final boolean isVpn;
71
72     public LinkstateNlriParser(final boolean isVpn) {
73         this.isVpn = isVpn;
74     }
75
76     private static NodeIdentifier parseLink(final CLinkstateDestinationBuilder builder, final ByteBuf buffer, final LocalNodeDescriptors localDescriptors)
77             throws BGPParsingException {
78         final int type = buffer.readUnsignedShort();
79         final int length = buffer.readUnsignedShort();
80         final NodeIdentifier remote = null;
81         RemoteNodeDescriptors remoteDescriptors = null;
82         if (type == REMOTE_NODE_DESCRIPTORS) {
83             remoteDescriptors = (RemoteNodeDescriptors)NodeNlriParser.parseNodeDescriptors(buffer.readSlice(length), NlriType.Link, false);
84         }
85         builder.setObjectType(new LinkCaseBuilder()
86             .setLocalNodeDescriptors(localDescriptors)
87             .setRemoteNodeDescriptors(remoteDescriptors)
88             .setLinkDescriptors(LinkNlriParser.parseLinkDescriptors(buffer.slice())).build());
89         return remote;
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      * @param isVpn flag which determines that destination has route distinguisher
97      * @return {@link CLinkstateDestination}
98      * @throws BGPParsingException if parsing was unsuccessful
99      */
100     public static List<CLinkstateDestination> parseNlri(final ByteBuf nlri, final boolean isVpn) throws BGPParsingException {
101         final List<CLinkstateDestination> dests = new ArrayList<>();
102         while (nlri.isReadable()) {
103             final CLinkstateDestinationBuilder builder = new CLinkstateDestinationBuilder();
104             final NlriType type = NlriType.forValue(nlri.readUnsignedShort());
105
106             // length means total length of the tlvs including route distinguisher not including the type field
107             final int length = nlri.readUnsignedShort();
108             RouteDistinguisher distinguisher = null;
109             if (isVpn) {
110                 // this parses route distinguisher
111                 distinguisher = new RouteDistinguisher(BigInteger.valueOf(nlri.readLong()));
112                 builder.setDistinguisher(distinguisher);
113             }
114             // parse source protocol
115             final ProtocolId sp = ProtocolId.forValue(nlri.readByte());
116             builder.setProtocolId(sp);
117
118             // parse identifier
119             final Identifier identifier = new Identifier(BigInteger.valueOf(nlri.readLong()));
120             builder.setIdentifier(identifier);
121
122             // if we are dealing with linkstate nodes/links, parse local node descriptor
123             NodeIdentifier localDescriptor = null;
124             final int localtype = nlri.readUnsignedShort();
125             final int locallength = nlri.readUnsignedShort();
126             if (localtype == LOCAL_NODE_DESCRIPTORS) {
127                 localDescriptor = NodeNlriParser.parseNodeDescriptors(nlri.readSlice(locallength), type, true);
128             }
129             final int restLength = length - (isVpn ? ROUTE_DISTINGUISHER_LENGTH : 0) - PROTOCOL_ID_LENGTH - IDENTIFIER_LENGTH
130                 - TYPE_LENGTH - LENGTH_SIZE - locallength;
131             LOG.trace("Restlength {}", restLength);
132             final ByteBuf rest = nlri.readSlice(restLength);
133             switch (type) {
134             case Link:
135                 parseLink(builder, rest, (LocalNodeDescriptors) localDescriptor);
136                 break;
137             case Ipv4Prefix:
138                 builder.setObjectType(new PrefixCaseBuilder()
139                     .setAdvertisingNodeDescriptors((AdvertisingNodeDescriptors)localDescriptor)
140                     .setPrefixDescriptors(PrefixNlriParser.parsePrefixDescriptors(rest, true)).build());
141                 break;
142             case Ipv6Prefix:
143                 builder.setObjectType(new PrefixCaseBuilder()
144                     .setAdvertisingNodeDescriptors((AdvertisingNodeDescriptors)localDescriptor)
145                     .setPrefixDescriptors(PrefixNlriParser.parsePrefixDescriptors(rest, false)).build());
146                 break;
147             case Node:
148                 // node nlri is already parsed as it contains only the common fields for node and link nlri
149                 builder.setObjectType(new NodeCaseBuilder().setNodeDescriptors((NodeDescriptors)localDescriptor).build());
150                 break;
151             default:
152                 break;
153             }
154             dests.add(builder.build());
155         }
156         return dests;
157     }
158
159     @Override
160     public void parseNlri(final ByteBuf nlri, final MpUnreachNlriBuilder builder) throws BGPParsingException {
161         if (!nlri.isReadable()) {
162             return;
163         }
164         final List<CLinkstateDestination> dst = parseNlri(nlri, this.isVpn);
165
166         builder.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(
167             new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.update.path.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationLinkstateCaseBuilder().setDestinationLinkstate(
168                 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.update.path.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.destination.linkstate._case.DestinationLinkstateBuilder().setCLinkstateDestination(
169                     dst).build()).build()).build());
170     }
171
172     @Override
173     public void parseNlri(final ByteBuf nlri, final MpReachNlriBuilder builder) throws BGPParsingException {
174         if (!nlri.isReadable()) {
175             return;
176         }
177         final List<CLinkstateDestination> dst = parseNlri(nlri, this.isVpn);
178
179         builder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(
180             new DestinationLinkstateCaseBuilder().setDestinationLinkstate(
181                 new DestinationLinkstateBuilder().setCLinkstateDestination(dst).build()).build()).build());
182     }
183
184     /**
185      * Serializes Linkstate NLRI to byte array. We need this as NLRI serves as a key in upper layers.
186      *
187      * @param destination Linkstate NLRI to be serialized
188      * @param buffer where Linkstate NLRI will be serialized
189      */
190     public static void serializeNlri(final CLinkstateDestination destination, final ByteBuf buffer) {
191         final ByteBuf nlriByteBuf = Unpooled.buffer();
192         if (destination.getDistinguisher() != null) {
193             nlriByteBuf.writeBytes(destination.getDistinguisher().getValue().toByteArray());
194         }
195         nlriByteBuf.writeByte(destination.getProtocolId().getIntValue());
196         nlriByteBuf.writeLong(destination.getIdentifier().getValue().longValue());
197         final ByteBuf ldescs = Unpooled.buffer();
198         final ObjectType ot = destination.getObjectType();
199         NlriType nlriType = null;
200         if (ot instanceof PrefixCase) {
201             final PrefixCase pCase = (PrefixCase)destination.getObjectType();
202             NodeNlriParser.serializeNodeDescriptors(pCase.getAdvertisingNodeDescriptors(), ldescs);
203             TlvUtil.writeTLV(LOCAL_NODE_DESCRIPTORS, ldescs, nlriByteBuf);
204             if (pCase.getPrefixDescriptors() != null) {
205                 PrefixNlriParser.serializePrefixDescriptors(pCase.getPrefixDescriptors(), nlriByteBuf);
206                 if (pCase.getPrefixDescriptors().getIpReachabilityInformation().getIpv4Prefix() != null) {
207                     nlriType = NlriType.Ipv4Prefix;
208                 } else {
209                     nlriType = NlriType.Ipv6Prefix;
210                 }
211             }
212         } else if (ot instanceof LinkCase) {
213             final LinkCase lCase = (LinkCase)destination.getObjectType();
214             NodeNlriParser.serializeNodeDescriptors(lCase.getLocalNodeDescriptors(), ldescs);
215             TlvUtil.writeTLV(LOCAL_NODE_DESCRIPTORS, ldescs, nlriByteBuf);
216             final ByteBuf rdescs = Unpooled.buffer();
217             NodeNlriParser.serializeNodeDescriptors(lCase.getRemoteNodeDescriptors(), rdescs);
218             TlvUtil.writeTLV(REMOTE_NODE_DESCRIPTORS, rdescs, nlriByteBuf);
219             if (lCase.getLinkDescriptors() != null) {
220                 LinkNlriParser.serializeLinkDescriptors(lCase.getLinkDescriptors(), nlriByteBuf);
221             }
222             nlriType = NlriType.Link;
223         } else if (ot instanceof NodeCase) {
224             final NodeCase nCase = (NodeCase)destination.getObjectType();
225             NodeNlriParser.serializeNodeDescriptors(nCase.getNodeDescriptors(), ldescs);
226             TlvUtil.writeTLV(LOCAL_NODE_DESCRIPTORS, ldescs, nlriByteBuf);
227             nlriType = NlriType.Node;
228         } else {
229             LOG.warn("Unknown NLRI Type.");
230         }
231         TlvUtil.writeTLV(nlriType.getIntValue(), nlriByteBuf, buffer);
232     }
233
234     @Override
235     public void serializeAttribute(final DataObject attribute, final ByteBuf byteAggregator) {
236         Preconditions.checkArgument(attribute instanceof PathAttributes, "Attribute parameter is not a PathAttribute object.");
237         final PathAttributes pathAttributes = (PathAttributes) attribute;
238         final PathAttributes1 pathAttributes1 = pathAttributes.getAugmentation(PathAttributes1.class);
239         final PathAttributes2 pathAttributes2 = pathAttributes.getAugmentation(PathAttributes2.class);
240         if (pathAttributes1 != null) {
241             final AdvertizedRoutes routes = (pathAttributes1.getMpReachNlri()).getAdvertizedRoutes();
242             if (routes != null &&
243                 routes.getDestinationType()
244                 instanceof
245                 org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLinkstateCase) {
246                 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLinkstateCase
247                 linkstateCase = (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLinkstateCase) routes.getDestinationType();
248
249                 for (final CLinkstateDestination cLinkstateDestination : linkstateCase.getDestinationLinkstate().getCLinkstateDestination()) {
250                     serializeNlri(cLinkstateDestination, byteAggregator);
251                 }
252             }
253         } else if (pathAttributes2 != null) {
254             final MpUnreachNlri mpUnreachNlri = pathAttributes2.getMpUnreachNlri();
255             if (mpUnreachNlri.getWithdrawnRoutes() != null && mpUnreachNlri.getWithdrawnRoutes().getDestinationType() instanceof DestinationLinkstateCase) {
256                 final DestinationLinkstateCase linkstateCase = (DestinationLinkstateCase) mpUnreachNlri.getWithdrawnRoutes().getDestinationType();
257                 for (final CLinkstateDestination cLinkstateDestination : linkstateCase.getDestinationLinkstate().getCLinkstateDestination()) {
258                     serializeNlri(cLinkstateDestination, byteAggregator);
259                 }
260             }
261         }
262     }
263 }