2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.protocol.bgp.linkstate.nlri;
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;
62 * Parser and serializer for Linkstate NLRI.
64 public final class LinkstateNlriParser implements NlriParser, NlriSerializer {
66 private static final Logger LOG = LoggerFactory.getLogger(LinkstateNlriParser.class);
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;
72 private static final int TYPE_LENGTH = 2;
73 private static final int LENGTH_SIZE = 2;
75 private static final int LOCAL_NODE_DESCRIPTORS_TYPE = 256;
76 private static final int REMOTE_NODE_DESCRIPTORS_TYPE = 257;
79 public static final NodeIdentifier OBJECT_TYPE_NID = new NodeIdentifier(ObjectType.QNAME);
81 public static final NodeIdentifier NODE_DESCRIPTORS_NID = new NodeIdentifier(NodeDescriptors.QNAME);
83 public static final NodeIdentifier LOCAL_NODE_DESCRIPTORS_NID = new NodeIdentifier(LocalNodeDescriptors.QNAME);
85 public static final NodeIdentifier REMOTE_NODE_DESCRIPTORS_NID = new NodeIdentifier(RemoteNodeDescriptors.QNAME);
87 public static final NodeIdentifier ADVERTISING_NODE_DESCRIPTORS_NID = new NodeIdentifier(AdvertisingNodeDescriptors.QNAME);
89 public static final NodeIdentifier PREFIX_DESCRIPTORS_NID = new NodeIdentifier(PrefixDescriptors.QNAME);
91 public static final NodeIdentifier LINK_DESCRIPTORS_NID = new NodeIdentifier(LinkDescriptors.QNAME);
94 public static final NodeIdentifier DISTINGUISHER_NID = new NodeIdentifier(QName.create(CLinkstateDestination.QNAME, "distinguisher").intern());
96 public static final NodeIdentifier PROTOCOL_ID_NID = new NodeIdentifier(QName.create(CLinkstateDestination.QNAME, "protocol-id").intern());
98 public static final NodeIdentifier IDENTIFIER_NID = new NodeIdentifier(QName.create(CLinkstateDestination.QNAME, "identifier").intern());
100 private final boolean isVpn;
102 public LinkstateNlriParser(final boolean isVpn) {
108 * Parses common parts for Link State Nodes, Links and Prefixes, that includes protocol ID and identifier tlv.
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
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());
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;
125 // this parses route distinguisher
126 distinguisher = new RouteDistinguisher(BigInteger.valueOf(nlri.readLong()));
127 builder.setDistinguisher(distinguisher);
129 // parse source protocol
130 final ProtocolId sp = ProtocolId.forValue(nlri.readByte());
131 builder.setProtocolId(sp);
134 final Identifier identifier = new Identifier(BigInteger.valueOf(nlri.readLong()));
135 builder.setIdentifier(identifier);
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;
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);
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);
151 builder.setObjectType(SimpleNlriTypeRegistry.getInstance().parseNlriType(nlri, type, localDescriptor, rest));
152 dests.add(builder.build());
158 public void parseNlri(final ByteBuf nlri, final MpUnreachNlriBuilder builder) throws BGPParsingException {
159 if (!nlri.isReadable()) {
162 final List<CLinkstateDestination> dst = parseNlri(nlri, this.isVpn);
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());
171 public void parseNlri(final ByteBuf nlri, final MpReachNlriBuilder builder) throws BGPParsingException {
172 if (!nlri.isReadable()) {
175 final List<CLinkstateDestination> dst = parseNlri(nlri, this.isVpn);
177 builder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(
178 new DestinationLinkstateCaseBuilder().setDestinationLinkstate(
179 new DestinationLinkstateBuilder().setCLinkstateDestination(dst).build()).build()).build());
183 * Serializes Linkstate NLRI to byte array. We need this as NLRI serves as a key in upper layers.
185 * @param destination Linkstate NLRI to be serialized
186 * @param buffer where Linkstate NLRI will be serialized
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());
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);
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()
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();
216 for (final CLinkstateDestination cLinkstateDestination : linkstateCase.getDestinationLinkstate().getCLinkstateDestination()) {
217 serializeNlri(cLinkstateDestination, byteAggregator);
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);
232 private static int domProtocolIdValue(final String protocolId) {
233 switch (protocolId) {
235 return ProtocolId.IsisLevel1.getIntValue();
237 return ProtocolId.IsisLevel2.getIntValue();
239 return ProtocolId.Ospf.getIntValue();
241 return ProtocolId.Direct.getIntValue();
243 return ProtocolId.Static.getIntValue();
245 return ProtocolId.OspfV3.getIntValue();
247 return ProtocolId.RsvpTe.getIntValue();
249 return ProtocolId.BgpEpe.getIntValue();
250 case "segment-routing":
251 return ProtocolId.SegmentRouting.getIntValue();
257 public static CLinkstateDestination extractLinkstateDestination(final DataContainerNode<? extends PathArgument> linkstate) {
258 final CLinkstateDestinationBuilder builder = new CLinkstateDestinationBuilder();
259 serializeCommonParts(builder, linkstate);
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));
271 LOG.warn("Unknown Object Type: {}.", objectType);
273 return builder.build();
276 private static void serializeNodeDescriptor(final CLinkstateDestinationBuilder builder, final ChoiceNode objectType) {
277 final NodeCaseBuilder nodeBuilder = new NodeCaseBuilder();
279 nodeBuilder.setNodeDescriptors(NodeNlriParser.serializeNodeDescriptors((ContainerNode) objectType.getChild(NODE_DESCRIPTORS_NID).get()));
280 builder.setObjectType(nodeBuilder.build());
283 private static void serializeLocalNodeDescriptor(final CLinkstateDestinationBuilder builder, final ChoiceNode objectType) {
284 // link local node descriptors
285 final LinkCaseBuilder linkBuilder = new LinkCaseBuilder();
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()));
293 final Optional<DataContainerChild<? extends PathArgument, ?>> linkDescriptors = objectType.getChild(LINK_DESCRIPTORS_NID);
294 if (linkDescriptors.isPresent()) {
295 linkBuilder.setLinkDescriptors(LinkNlriParser.serializeLinkDescriptors((ContainerNode) linkDescriptors.get()));
297 builder.setObjectType(linkBuilder.build());
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()));
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()));
311 builder.setObjectType(prefixBuilder.build());
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()));
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())));
325 final Optional<DataContainerChild<? extends PathArgument, ?>> identifier = linkstate.getChild(IDENTIFIER_NID);
326 if (identifier.isPresent()) {
327 builder.setIdentifier(new Identifier((BigInteger) identifier.get().getValue()));