f1b4bd05e91f355adfb170ee050c67aca2ddb5ac
[bgpcep.git] / bgp / linkstate / src / main / java / org / opendaylight / protocol / bgp / linkstate / nlri / PrefixNlriParser.java
1 /*
2  * Copyright (c) 2014 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.primitives.UnsignedBytes;
13 import io.netty.buffer.ByteBuf;
14 import io.netty.buffer.ByteBufUtil;
15 import io.netty.buffer.Unpooled;
16 import org.opendaylight.protocol.bgp.linkstate.spi.TlvUtil;
17 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
18 import org.opendaylight.protocol.util.ByteArray;
19 import org.opendaylight.protocol.util.Ipv4Util;
20 import org.opendaylight.protocol.util.Ipv6Util;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.NlriType;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.OspfRouteType;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.TopologyIdentifier;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.prefix._case.PrefixDescriptors;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.object.type.prefix._case.PrefixDescriptorsBuilder;
29 import org.opendaylight.yangtools.yang.common.QName;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
31 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
32 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 @VisibleForTesting
38 public final class PrefixNlriParser {
39
40     private static final Logger LOG = LoggerFactory.getLogger(PrefixNlriParser.class);
41
42     private PrefixNlriParser() {
43         throw new UnsupportedOperationException();
44     }
45
46     /* Prefix Descriptor TLVs */
47     private static final int OSPF_ROUTE_TYPE = 264;
48     private static final int IP_REACHABILITY = 265;
49
50     /* Prefix Descriptor QNames */
51     private static final NodeIdentifier OSPF_ROUTE_NID = new NodeIdentifier(QName.cachedReference(QName.create(PrefixDescriptors.QNAME, "ospf-route-type")));
52     private static final NodeIdentifier IP_REACH_NID = new NodeIdentifier(QName.cachedReference(QName.create(PrefixDescriptors.QNAME, "ip-reachability-information")));
53
54     static PrefixDescriptors parsePrefixDescriptors(final ByteBuf buffer, final boolean ipv4) throws BGPParsingException {
55         final PrefixDescriptorsBuilder builder = new PrefixDescriptorsBuilder();
56         while (buffer.isReadable()) {
57             final int type = buffer.readUnsignedShort();
58             final int length = buffer.readUnsignedShort();
59             final ByteBuf value = buffer.readSlice(length);
60             if (LOG.isTraceEnabled()) {
61                 LOG.trace("Parsing Prefix Descriptor: {}", ByteBufUtil.hexDump(value));
62             }
63             switch (type) {
64             case TlvUtil.MULTI_TOPOLOGY_ID:
65                 final TopologyIdentifier topologyId = new TopologyIdentifier(value.readShort() & TlvUtil.TOPOLOGY_ID_OFFSET);
66                 builder.setMultiTopologyId(topologyId);
67                 LOG.trace("Parsed Topology Identifier: {}", topologyId);
68                 break;
69             case OSPF_ROUTE_TYPE:
70                 final int rt = value.readByte();
71                 final OspfRouteType routeType = OspfRouteType.forValue(rt);
72                 if (routeType == null) {
73                     throw new BGPParsingException("Unknown OSPF Route Type: " + rt);
74                 }
75                 builder.setOspfRouteType(routeType);
76                 LOG.trace("Parser RouteType: {}", routeType);
77                 break;
78             case IP_REACHABILITY:
79                 IpPrefix prefix = null;
80                 final int prefixLength = value.readByte();
81                 final int size = prefixLength / Byte.SIZE + ((prefixLength % Byte.SIZE == 0) ? 0 : 1);
82                 if (size != value.readableBytes()) {
83                     LOG.debug("Expected length {}, actual length {}.", size, value.readableBytes());
84                     throw new BGPParsingException("Illegal length of IP reachability TLV: " + (value.readableBytes()));
85                 }
86                 prefix = (ipv4) ? new IpPrefix(Ipv4Util.prefixForBytes(ByteArray.readBytes(value, size), prefixLength)):
87                     new IpPrefix(Ipv6Util.prefixForBytes(ByteArray.readBytes(value, size), prefixLength));
88                 builder.setIpReachabilityInformation(prefix);
89                 LOG.trace("Parsed IP reachability info: {}", prefix);
90                 break;
91             default:
92                 throw new BGPParsingException("Prefix Descriptor not recognized, type: " + type);
93             }
94         }
95         LOG.debug("Finished parsing Prefix descriptors.");
96         return builder.build();
97     }
98
99     static void serializePrefixDescriptors(final PrefixDescriptors descriptors, final ByteBuf buffer) {
100         if (descriptors.getMultiTopologyId() != null) {
101             TlvUtil.writeTLV(TlvUtil.MULTI_TOPOLOGY_ID, Unpooled.copyShort(descriptors.getMultiTopologyId().getValue()), buffer);
102         }
103         if (descriptors.getOspfRouteType() != null) {
104             TlvUtil.writeTLV(OSPF_ROUTE_TYPE,
105                 Unpooled.wrappedBuffer(new byte[] {UnsignedBytes.checkedCast(descriptors.getOspfRouteType().getIntValue()) }), buffer);
106         }
107         if (descriptors.getIpReachabilityInformation() != null) {
108             final IpPrefix prefix = descriptors.getIpReachabilityInformation();
109             byte[] prefixBytes = null;
110             if (prefix.getIpv4Prefix() != null) {
111                 prefixBytes = Ipv4Util.bytesForPrefixBegin(prefix.getIpv4Prefix());
112             } else if (prefix.getIpv6Prefix() != null) {
113                 prefixBytes = Ipv6Util.bytesForPrefixBegin(prefix.getIpv6Prefix());
114             }
115             TlvUtil.writeTLV(IP_REACHABILITY, Unpooled.wrappedBuffer(prefixBytes), buffer);
116         }
117     }
118
119     private static int domOspfRouteTypeValue(final String ospfRouteType) {
120         switch(ospfRouteType) {
121         case "intra-area":
122             return 1;
123         case "inter-area":
124             return 2;
125         case "external1":
126             return 3;
127         case "external2":
128             return 4;
129         case "nssa1":
130             return 5;
131         case "nssa2":
132             return 6;
133         default:
134             return 0;
135         }
136     }
137
138     static NlriType serializePrefixDescriptors(final ContainerNode descriptors, final ByteBuf buffer) {
139         if (descriptors.getChild(TlvUtil.MULTI_TOPOLOGY_NID).isPresent()) {
140             TlvUtil.writeTLV(TlvUtil.MULTI_TOPOLOGY_ID, Unpooled.copyShort((Short)descriptors.getChild(TlvUtil.MULTI_TOPOLOGY_NID).get().getValue()), buffer);
141         }
142         final Optional<DataContainerChild<? extends PathArgument, ?>> ospfRoute = descriptors.getChild(OSPF_ROUTE_NID);
143         if (ospfRoute.isPresent()) {
144             // DOM representation contains values as are in the model, not as are in generated enum
145             TlvUtil.writeTLV(OSPF_ROUTE_TYPE,
146                 Unpooled.wrappedBuffer(new byte[] {UnsignedBytes.checkedCast(domOspfRouteTypeValue((String)ospfRoute.get().getValue())) }), buffer);
147         }
148         byte[] prefixBytes = null;
149         NlriType prefixType = null;
150         if (descriptors.getChild(IP_REACH_NID).isPresent()) {
151             final String prefix = (String)descriptors.getChild(IP_REACH_NID).get().getValue();
152             // DOM data does not have any information what kind of prefix is it holding,
153             // therefore we need to rely on the pattern matcher in Ipv4Prefix constructor
154             try {
155                 prefixBytes = Ipv4Util.bytesForPrefixBegin(new Ipv4Prefix(prefix));
156                 prefixType = NlriType.Ipv4Prefix;
157             } catch(final IllegalArgumentException e) {
158                 prefixBytes = Ipv6Util.bytesForPrefixBegin(new Ipv6Prefix(prefix));
159                 prefixType = NlriType.Ipv6Prefix;
160             }
161             TlvUtil.writeTLV(IP_REACHABILITY, Unpooled.wrappedBuffer(prefixBytes), buffer);
162         }
163         return prefixType;
164     }
165 }