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