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.parser.impl.message.update;
10 import java.math.BigInteger;
11 import java.util.Arrays;
13 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
14 import org.opendaylight.protocol.bgp.parser.spi.NlriParser;
15 import org.opendaylight.protocol.bgp.parser.spi.NlriUtil;
16 import org.opendaylight.protocol.concepts.Ipv4Util;
17 import org.opendaylight.protocol.concepts.Ipv6Util;
18 import org.opendaylight.protocol.util.ByteArray;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.AreaIdentifier;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.DomainIdentifier;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.Identifier;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.Ipv4InterfaceIdentifier;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.Ipv6InterfaceIdentifier;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.NlriType;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.NodeIdentifier;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.OspfInterfaceIdentifier;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.OspfRouteType;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.ProtocolId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.RouteDistinguisher;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.TopologyIdentifier;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.isis.lan.identifier.IsIsRouterIdentifier;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.isis.lan.identifier.IsIsRouterIdentifierBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.CLinkstateDestination;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.CLinkstateDestinationBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.c.linkstate.destination.LinkDescriptors;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.c.linkstate.destination.LinkDescriptorsBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.c.linkstate.destination.LocalNodeDescriptors;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.c.linkstate.destination.LocalNodeDescriptorsBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.c.linkstate.destination.PrefixDescriptors;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.c.linkstate.destination.PrefixDescriptorsBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.linkstate.destination.c.linkstate.destination.RemoteNodeDescriptors;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.CRouterIdentifier;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.CIsisNodeBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.CIsisPseudonodeBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.COspfNodeBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.COspfPseudonodeBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.c.isis.node.IsisNodeBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.c.isis.pseudonode.IsisPseudonodeBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.c.ospf.node.OspfNodeBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.node.identifier.c.router.identifier.c.ospf.pseudonode.OspfPseudonodeBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLinkstateBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.destination.DestinationType;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.update.path.attributes.MpReachNlriBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.update.path.attributes.MpUnreachNlriBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.update.path.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.update.path.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nps.concepts.rev130930.IsoSystemIdentifier;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
63 import com.google.common.primitives.UnsignedBytes;
65 final class LinkstateNlriParser implements NlriParser {
66 private static final Logger logger = LoggerFactory.getLogger(LinkstateNlriParser.class);
67 private static final int ROUTE_DISTINGUISHER_LENGTH = 8;
68 private static final int PROTOCOL_ID_LENGTH = 1;
69 private static final int IDENTIFIER_LENGTH = 8;
71 private static final int TYPE_LENGTH = 2;
72 private static final int LENGTH_SIZE = 2;
74 private final boolean isVpn;
76 public LinkstateNlriParser(final boolean isVpn) {
80 private static NodeIdentifier parseLink(final CLinkstateDestinationBuilder builder, final byte[] bytes) throws BGPParsingException {
82 final int type = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
83 byteOffset += TYPE_LENGTH;
84 final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
85 byteOffset += LENGTH_SIZE;
86 final NodeIdentifier remote = null;
88 builder.setRemoteNodeDescriptors((RemoteNodeDescriptors) parseNodeDescriptors(ByteArray.subByte(bytes, byteOffset, length)));
91 builder.setLinkDescriptors(parseLinkDescriptors(ByteArray.subByte(bytes, byteOffset, bytes.length - byteOffset)));
95 private static LinkDescriptors parseLinkDescriptors(final byte[] bytes) throws BGPParsingException {
97 final LinkDescriptorsBuilder builder = new LinkDescriptorsBuilder();
98 while (byteOffset != bytes.length) {
99 final int type = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
100 byteOffset += TYPE_LENGTH;
101 final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
102 byteOffset += LENGTH_SIZE;
103 final byte[] value = ByteArray.subByte(bytes, byteOffset, length);
104 logger.debug("Parsing Link Descriptor: {}", Arrays.toString(value));
107 builder.setLinkLocalIdentifier(ByteArray.subByte(value, 0, 4));
108 builder.setLinkRemoteIdentifier(ByteArray.subByte(value, 4, 4));
109 logger.trace("Parsed link local {} remote {} Identifiers.", builder.getLinkLocalIdentifier(),
110 builder.getLinkRemoteIdentifier());
113 final Ipv4InterfaceIdentifier lipv4 = new Ipv4InterfaceIdentifier(Ipv4Util.addressForBytes(value));
114 builder.setIpv4InterfaceAddress(lipv4);
115 logger.trace("Parsed IPv4 interface address {}.", lipv4);
118 final Ipv4InterfaceIdentifier ripv4 = new Ipv4InterfaceIdentifier(Ipv4Util.addressForBytes(value));
119 builder.setIpv4NeighborAddress(ripv4);
120 logger.trace("Parsed IPv4 neighbor address {}.", ripv4);
123 final Ipv6InterfaceIdentifier lipv6 = new Ipv6InterfaceIdentifier(Ipv6Util.addressForBytes(value));
124 builder.setIpv6InterfaceAddress(lipv6);
125 logger.trace("Parsed IPv6 interface address {}.", lipv6);
128 final Ipv6InterfaceIdentifier ripv6 = new Ipv6InterfaceIdentifier(Ipv6Util.addressForBytes(value));
129 builder.setIpv6NeighborAddress(ripv6);
130 logger.trace("Parsed IPv6 neighbor address {}.", ripv6);
133 final TopologyIdentifier topId = new TopologyIdentifier(ByteArray.bytesToInt(value) & 0x3fff);
134 builder.setMultiTopologyId(topId);
135 logger.trace("Parsed topology identifier {}.", topId);
138 throw new BGPParsingException("Link Descriptor not recognized, type: " + type);
140 byteOffset += length;
142 logger.debug("Finished parsing Link descriptors.");
143 return builder.build();
146 private static NodeIdentifier parseNodeDescriptors(final byte[] bytes) throws BGPParsingException {
148 AsNumber asnumber = null;
149 DomainIdentifier bgpId = null;
150 AreaIdentifier ai = null;
151 CRouterIdentifier routerId = null;
152 while (byteOffset != bytes.length) {
153 final int type = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
154 byteOffset += TYPE_LENGTH;
155 final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
156 byteOffset += LENGTH_SIZE;
157 final byte[] value = ByteArray.subByte(bytes, byteOffset, length);
158 logger.debug("Parsing Node Descriptor: {}", Arrays.toString(value));
161 asnumber = new AsNumber(ByteArray.bytesToLong(value));
162 logger.trace("Parsed AS number {}", asnumber);
165 bgpId = new DomainIdentifier(value);
166 logger.trace("Parsed bgpId {}", bgpId);
169 ai = new AreaIdentifier(value);
170 logger.trace("Parsed area identifier {}", ai);
173 if (value.length == 6) {
174 routerId = new CIsisNodeBuilder().setIsisNode(
175 new IsisNodeBuilder().setIsoSystemId(new IsoSystemIdentifier(ByteArray.subByte(value, 0, 6))).build()).build();
176 } else if (value.length == 7) {
178 logger.warn("PSN octet is 0. Ignoring System ID.");
179 routerId = new CIsisNodeBuilder().setIsisNode(
180 new IsisNodeBuilder().setIsoSystemId(new IsoSystemIdentifier(ByteArray.subByte(value, 0, 6))).build()).build();
183 final IsIsRouterIdentifier iri = new IsIsRouterIdentifierBuilder().setIsoSystemId(
184 new IsoSystemIdentifier(ByteArray.subByte(value, 0, 6))).build();
185 routerId = new CIsisPseudonodeBuilder().setIsisPseudonode(
186 new IsisPseudonodeBuilder().setIsIsRouterIdentifier(iri).setPsn((short) UnsignedBytes.toInt(value[6])).build()).build();
188 } else if (value.length == 4) {
189 routerId = new COspfNodeBuilder().setOspfNode(
190 new OspfNodeBuilder().setOspfRouterId(ByteArray.subByte(value, 0, 4)).build()).build();
191 } else if (value.length == 8) {
192 final byte[] o = ByteArray.subByte(value, 0, 4); // FIXME: OSPFv3 vs OSPFv2
193 final OspfInterfaceIdentifier a = new OspfInterfaceIdentifier(ByteArray.subByte(value, 4, 4));
194 routerId = new COspfPseudonodeBuilder().setOspfPseudonode(
195 new OspfPseudonodeBuilder().setOspfRouterId(o).setLanInterface(a).build()).build();
197 logger.trace("Parsed Router Identifier {}", routerId);
200 throw new BGPParsingException("Node Descriptor not recognized, type: " + type);
202 byteOffset += length;
204 logger.debug("Finished parsing Node descriptors.");
205 return new LocalNodeDescriptorsBuilder().setAsNumber(asnumber).setDomainId(bgpId).setAreaId(ai).setCRouterIdentifier(routerId).build();
208 private static PrefixDescriptors parsePrefixDescriptors(final NodeIdentifier localDescriptor, final byte[] bytes) throws BGPParsingException {
210 final PrefixDescriptorsBuilder builder = new PrefixDescriptorsBuilder();
211 while (byteOffset != bytes.length) {
212 final int type = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TYPE_LENGTH));
213 byteOffset += TYPE_LENGTH;
214 final int length = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, LENGTH_SIZE));
215 byteOffset += LENGTH_SIZE;
216 final byte[] value = ByteArray.subByte(bytes, byteOffset, length);
217 logger.trace("Parsing Prefix Descriptor: {}", Arrays.toString(value));
220 final TopologyIdentifier topologyId = new TopologyIdentifier(ByteArray.bytesToInt(value) & 0x3fff);
221 builder.setMultiTopologyId(topologyId);
222 logger.trace("Parsed Topology Identifier: {}", topologyId);
225 final int rt = ByteArray.bytesToInt(value);
226 final OspfRouteType routeType = OspfRouteType.forValue(rt);
227 if (routeType == null) {
228 throw new BGPParsingException("Unknown OSPF Route Type: " + rt);
230 builder.setOspfRouteType(routeType);
231 logger.trace("Parser RouteType: {}", routeType);
234 IpPrefix prefix = null;
235 final int prefixLength = UnsignedBytes.toInt(value[0]);
236 final int size = prefixLength / 8 + ((prefixLength % 8 == 0) ? 0 : 1);
237 if (size != value.length - 1) {
238 logger.debug("Expected length {}, actual length {}.", size, value.length - 1);
239 throw new BGPParsingException("Illegal length of IP reachability TLV: " + (value.length - 1));
242 prefix = new IpPrefix(Ipv4Util.prefixForBytes(ByteArray.subByte(value, 1, size), prefixLength));
244 prefix = new IpPrefix(Ipv6Util.prefixForBytes(ByteArray.subByte(value, 1, size), prefixLength));
246 builder.setIpReachabilityInformation(prefix);
247 logger.trace("Parsed IP reachability info: {}", prefix);
250 throw new BGPParsingException("Prefix Descriptor not recognized, type: " + type);
252 byteOffset += length;
254 logger.debug("Finished parsing Prefix descriptors.");
255 return builder.build();
259 * Parses common parts for Link State Nodes, Links and Prefixes, that includes protocol ID and identifier tlv.
262 * @return BGPLinkMP or BGPNodeMP
263 * @throws BGPParsingException
265 private final CLinkstateDestination parseNlri(final byte[] nlri) throws BGPParsingException {
266 if (nlri.length == 0) {
271 final CLinkstateDestinationBuilder builder = new CLinkstateDestinationBuilder();
273 while (byteOffset != nlri.length) {
274 final NlriType type = NlriType.forValue(ByteArray.bytesToInt(ByteArray.subByte(nlri, byteOffset, TYPE_LENGTH)));
275 builder.setNlriType(type);
277 byteOffset += TYPE_LENGTH;
278 // length means total length of the tlvs including route distinguisher not including the type field
279 final int length = ByteArray.bytesToInt(ByteArray.subByte(nlri, byteOffset, LENGTH_SIZE));
280 byteOffset += LENGTH_SIZE;
281 RouteDistinguisher distinguisher = null;
283 // this parses route distinguisher
284 distinguisher = new RouteDistinguisher(BigInteger.valueOf(ByteArray.bytesToLong(ByteArray.subByte(nlri, byteOffset,
285 ROUTE_DISTINGUISHER_LENGTH))));
286 builder.setDistinguisher(distinguisher);
287 byteOffset += ROUTE_DISTINGUISHER_LENGTH;
289 // parse source protocol
290 final ProtocolId sp = ProtocolId.forValue(ByteArray.bytesToInt(ByteArray.subByte(nlri, byteOffset, PROTOCOL_ID_LENGTH)));
291 byteOffset += PROTOCOL_ID_LENGTH;
292 builder.setProtocolId(sp);
295 final Identifier identifier = new Identifier(BigInteger.valueOf(ByteArray.bytesToLong(ByteArray.subByte(nlri, byteOffset,
296 IDENTIFIER_LENGTH))));
297 byteOffset += IDENTIFIER_LENGTH;
298 builder.setIdentifier(identifier);
300 // if we are dealing with linkstate nodes/links, parse local node descriptor
301 NodeIdentifier localDescriptor = null;
303 final int localtype = ByteArray.bytesToInt(ByteArray.subByte(nlri, byteOffset, TYPE_LENGTH));
304 byteOffset += TYPE_LENGTH;
305 locallength = ByteArray.bytesToInt(ByteArray.subByte(nlri, byteOffset, LENGTH_SIZE));
306 byteOffset += LENGTH_SIZE;
307 if (localtype == 256) {
308 localDescriptor = parseNodeDescriptors(ByteArray.subByte(nlri, byteOffset, locallength));
310 byteOffset += locallength;
311 builder.setLocalNodeDescriptors((LocalNodeDescriptors) localDescriptor);
312 final int restLength = length - (isVpn ? ROUTE_DISTINGUISHER_LENGTH : 0)
313 - PROTOCOL_ID_LENGTH - IDENTIFIER_LENGTH - TYPE_LENGTH - LENGTH_SIZE - locallength;
314 logger.debug("Restlength {}", restLength);
317 parseLink(builder, ByteArray.subByte(nlri, byteOffset, restLength));
321 builder.setPrefixDescriptors(parsePrefixDescriptors(localDescriptor, ByteArray.subByte(nlri, byteOffset, restLength)));
324 // node nlri is already parsed as it contains only the common fields for node and link nlri
327 byteOffset += restLength;
329 return builder.build();
333 public final void parseNlri(final byte[] nlri, final MpUnreachNlriBuilder builder) throws BGPParsingException {
334 final CLinkstateDestination dst = parseNlri(nlri);
336 // FIXME: This cast is because of a bug in yangtools (augmented choice has no relationship with base choice)
337 final DestinationType s = (DestinationType)new DestinationLinkstateBuilder().setCLinkstateDestination(dst).build();
339 builder.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(s).build());
343 public final void parseNlri(final byte[] nlri, final byte[] nextHop, final MpReachNlriBuilder builder) throws BGPParsingException {
344 final CLinkstateDestination dst = parseNlri(nlri);
346 // FIXME: This cast is because of a bug in yangtools (augmented choice has no relationship with base choice)
347 final DestinationType s = (DestinationType)new DestinationLinkstateBuilder().setCLinkstateDestination(dst).build();
349 builder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(s).build());
350 NlriUtil.parseNextHop(nextHop, builder);