BUG-4692: Migrate TCP-MD5 support in bgp package to netty's native-epoll
[bgpcep.git] / bgp / linkstate / src / main / java / org / opendaylight / protocol / bgp / linkstate / attribute / PrefixAttributesParser.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.attribute;
9
10 import com.google.common.annotations.VisibleForTesting;
11 import com.google.common.collect.Multimap;
12 import io.netty.buffer.ByteBuf;
13 import io.netty.buffer.ByteBufUtil;
14 import io.netty.buffer.Unpooled;
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.Map.Entry;
18 import org.opendaylight.protocol.bgp.linkstate.attribute.sr.BindingSidLabelParser;
19 import org.opendaylight.protocol.bgp.linkstate.attribute.sr.Ipv6SrPrefixAttributesParser;
20 import org.opendaylight.protocol.bgp.linkstate.attribute.sr.RangeTlvParser;
21 import org.opendaylight.protocol.bgp.linkstate.attribute.sr.SrPrefixAttributesParser;
22 import org.opendaylight.protocol.bgp.linkstate.spi.TlvUtil;
23 import org.opendaylight.protocol.util.BitArray;
24 import org.opendaylight.protocol.util.ByteArray;
25 import org.opendaylight.protocol.util.Ipv4Util;
26 import org.opendaylight.protocol.util.Ipv6Util;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.ExtendedRouteTag;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.IgpBits.UpDown;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.ProtocolId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.RouteTag;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.path.attribute.LinkStateAttribute;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.path.attribute.link.state.attribute.PrefixAttributesCase;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.path.attribute.link.state.attribute.PrefixAttributesCaseBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.path.attribute.link.state.attribute.prefix.attributes._case.PrefixAttributes;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.linkstate.path.attribute.link.state.attribute.prefix.attributes._case.PrefixAttributesBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.prefix.state.IgpBits;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.prefix.state.IgpBitsBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.prefix.state.Ipv6SrPrefix;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.prefix.state.SrBindingSidLabels;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.prefix.state.SrPrefix;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.prefix.state.SrRange;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.IgpMetric;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 @VisibleForTesting
48 public final class PrefixAttributesParser {
49
50     private static final Logger LOG = LoggerFactory.getLogger(PrefixAttributesParser.class);
51
52     private PrefixAttributesParser() {
53         throw new UnsupportedOperationException();
54     }
55
56     private static final int ROUTE_TAG_LENGTH = 4;
57     private static final int EXTENDED_ROUTE_TAG_LENGTH = 8;
58
59     private static final int FLAGS_SIZE = 8;
60     private static final int UP_DOWN_BIT = 0;
61     private static final int OSPF_NO_UNICAST = 1;
62     private static final int OSPF_LOCAL_ADDRESS = 2;
63     private static final int OSPF_PROPAGATE_ADDRESS = 3;
64
65     /* Prefix Attribute TLVs */
66     private static final int IGP_FLAGS = 1152;
67     private static final int ROUTE_TAG = 1153;
68     private static final int EXTENDED_ROUTE_TAG = 1154;
69     private static final int PREFIX_METRIC = 1155;
70     private static final int FORWARDING_ADDRESS = 1156;
71     private static final int PREFIX_OPAQUE = 1157;
72
73     /* Segment routing TLV */
74     public static final int PREFIX_SID = 1158;
75     public static final int IPV6_PREFIX_SID = 1169;
76     public static final int RANGE = 1159;
77     public static final int BINDING_SID = 1160;
78
79     /**
80      * Parse prefix attributes.
81      *
82      * @param attributes key is the tlv type and value are the value bytes of the tlv
83      * @param protocolId to differentiate parsing methods
84      * @return {@link LinkStateAttribute}
85      */
86     static LinkStateAttribute parsePrefixAttributes(final Multimap<Integer, ByteBuf> attributes, final ProtocolId protocolId) {
87         final PrefixAttributesBuilder builder = new PrefixAttributesBuilder();
88         final List<RouteTag> routeTags = new ArrayList<>();
89         final List<ExtendedRouteTag> exRouteTags = new ArrayList<>();
90         for (final Entry<Integer, ByteBuf> entry : attributes.entries()) {
91             final int key = entry.getKey();
92             final ByteBuf value = entry.getValue();
93             LOG.trace("Prefix attribute TLV {}", key);
94             parseAttribute(key, value, protocolId, builder, routeTags, exRouteTags);
95         }
96         LOG.trace("Finished parsing Prefix Attributes.");
97         builder.setRouteTags(routeTags);
98         builder.setExtendedTags(exRouteTags);
99         return new PrefixAttributesCaseBuilder().setPrefixAttributes(builder.build()).build();
100     }
101
102     private static void parseAttribute(final int key, final ByteBuf value, final ProtocolId protocolId, final PrefixAttributesBuilder builder, final List<RouteTag> routeTags, final List<ExtendedRouteTag> exRouteTags) {
103         switch (key) {
104         case IGP_FLAGS:
105             final BitArray flags = BitArray.valueOf(value, FLAGS_SIZE);
106             final boolean upDownBit = flags.get(UP_DOWN_BIT);
107             final boolean ospfNoUnicast = flags.get(OSPF_NO_UNICAST);
108             final boolean ospfLocalAddress = flags.get(OSPF_LOCAL_ADDRESS);
109             final boolean ospfPropagateAddress = flags.get(OSPF_PROPAGATE_ADDRESS);
110             builder.setIgpBits(new IgpBitsBuilder().setUpDown(new UpDown(upDownBit))
111                 .setIsIsUpDown(upDownBit)
112                 .setOspfNoUnicast(ospfNoUnicast)
113                 .setOspfLocalAddress(ospfLocalAddress)
114                 .setOspfPropagateNssa(ospfPropagateAddress)
115                 .build());
116             LOG.debug("Parsed IGP flag (up/down bit) : {}", upDownBit);
117             break;
118         case ROUTE_TAG:
119             parseRouteTags(routeTags, value);
120             break;
121         case EXTENDED_ROUTE_TAG:
122             parseExtendedRouteTags(exRouteTags, value);
123             break;
124         case PREFIX_METRIC:
125             final IgpMetric metric = new IgpMetric(value.readUnsignedInt());
126             builder.setPrefixMetric(metric);
127             LOG.debug("Parsed Metric: {}", metric);
128             break;
129         case FORWARDING_ADDRESS:
130             final IpAddress fwdAddress = parseForwardingAddress(value);
131             builder.setOspfForwardingAddress(fwdAddress);
132             LOG.debug("Parsed FWD Address: {}", fwdAddress);
133             break;
134         case PREFIX_OPAQUE:
135             if (LOG.isDebugEnabled()) {
136                 LOG.debug("Parsed Opaque value: {}, not preserving it", ByteBufUtil.hexDump(value));
137             }
138             break;
139         case PREFIX_SID:
140             final SrPrefix prefix = SrPrefixAttributesParser.parseSrPrefix(value, protocolId);
141             builder.setSrPrefix(prefix);
142             LOG.debug("Parsed SR Prefix: {}", prefix);
143             break;
144         case IPV6_PREFIX_SID:
145             final Ipv6SrPrefix ipv6Prefix = Ipv6SrPrefixAttributesParser.parseSrIpv6Prefix(value);
146             builder.setIpv6SrPrefix(ipv6Prefix);
147             LOG.debug("Parsed Ipv6 SR Prefix: {}", ipv6Prefix);
148             break;
149         case RANGE:
150             final SrRange range = RangeTlvParser.parseSrRange(value, protocolId);
151             builder.setSrRange(range);
152             LOG.debug("Parsed SR Range: {}", range);
153             break;
154         case BINDING_SID:
155             final SrBindingSidLabels label = BindingSidLabelParser.parseBindingSidLabel(value, protocolId);
156             if (builder.getSrBindingSidLabels() != null) {
157                 builder.getSrBindingSidLabels().add(label);
158             } else {
159                 final List<SrBindingSidLabels> labels = new ArrayList<SrBindingSidLabels>();
160                 labels.add(label);
161                 builder.setSrBindingSidLabels(labels);
162             }
163             LOG.debug("Parsed SR Binding SID {}", label);
164             break;
165         default:
166             LOG.warn("TLV {} is not a valid prefix attribute, ignoring it", key);
167         }
168     }
169
170     private static void parseRouteTags(final List<RouteTag> routeTags, final ByteBuf value) {
171         while (value.isReadable()) {
172             final RouteTag routeTag = new RouteTag(ByteArray.readBytes(value, ROUTE_TAG_LENGTH));
173             routeTags.add(routeTag);
174             LOG.debug("Parsed Route Tag: {}", routeTag);
175         }
176     }
177
178     private static void parseExtendedRouteTags(final List<ExtendedRouteTag> exRouteTags, final ByteBuf value) {
179         while (value.isReadable()) {
180             final ExtendedRouteTag exRouteTag = new ExtendedRouteTag(ByteArray.readBytes(value, EXTENDED_ROUTE_TAG_LENGTH));
181             exRouteTags.add(exRouteTag);
182             LOG.debug("Parsed Extended Route Tag: {}", exRouteTag);
183         }
184     }
185
186     private static IpAddress parseForwardingAddress(final ByteBuf value) {
187         IpAddress fwdAddress = null;
188         switch (value.readableBytes()) {
189         case Ipv4Util.IP4_LENGTH:
190             fwdAddress = new IpAddress(Ipv4Util.addressForByteBuf(value));
191             break;
192         case Ipv6Util.IPV6_LENGTH:
193             fwdAddress = new IpAddress(Ipv6Util.addressForByteBuf(value));
194             break;
195         default:
196             LOG.debug("Ignoring unsupported forwarding address length {}", value.readableBytes());
197         }
198         return fwdAddress;
199     }
200
201     static void serializePrefixAttributes(final PrefixAttributesCase prefixAttributesCase, final ByteBuf byteAggregator) {
202         final PrefixAttributes prefixAtrributes = prefixAttributesCase.getPrefixAttributes();
203         if (prefixAtrributes.getIgpBits() != null) {
204             final BitArray igpBit = new BitArray(FLAGS_SIZE);
205             final IgpBits igpBits = prefixAtrributes.getIgpBits();
206             igpBit.set(UP_DOWN_BIT, igpBits.getUpDown().isUpDown() || igpBits.isIsIsUpDown());
207             igpBit.set(OSPF_NO_UNICAST, igpBits.isOspfNoUnicast());
208             igpBit.set(OSPF_LOCAL_ADDRESS, igpBits.isOspfLocalAddress());
209             igpBit.set(OSPF_PROPAGATE_ADDRESS, igpBits.isOspfPropagateNssa());
210             TlvUtil.writeTLV(IGP_FLAGS, Unpooled.wrappedBuffer(igpBit.array()), byteAggregator);
211         }
212         serializeRouteTags(prefixAtrributes.getRouteTags(), byteAggregator);
213         serializeExtendedRouteTags(prefixAtrributes.getExtendedTags(), byteAggregator);
214         if (prefixAtrributes.getPrefixMetric() != null) {
215             TlvUtil.writeTLV(PREFIX_METRIC, Unpooled.copyInt(prefixAtrributes.getPrefixMetric().getValue().intValue()), byteAggregator);
216         }
217         serializeForwardingAddress(prefixAtrributes.getOspfForwardingAddress(), byteAggregator);
218         if (prefixAtrributes.getSrPrefix() != null) {
219             final ByteBuf buffer = Unpooled.buffer();
220             SrPrefixAttributesParser.serializeSrPrefix(prefixAtrributes.getSrPrefix(), buffer);
221             TlvUtil.writeTLV(PREFIX_SID, buffer, byteAggregator);
222         }
223         if (prefixAtrributes.getIpv6SrPrefix() != null) {
224             final ByteBuf buffer = Unpooled.buffer();
225             Ipv6SrPrefixAttributesParser.serializeIpv6SrPrefix(prefixAtrributes.getIpv6SrPrefix(), buffer);
226             TlvUtil.writeTLV(IPV6_PREFIX_SID, buffer, byteAggregator);
227         }
228         if (prefixAtrributes.getSrRange() != null) {
229             final ByteBuf sidBuffer = Unpooled.buffer();
230             RangeTlvParser.serializeSrRange(prefixAtrributes.getSrRange(), sidBuffer);
231             TlvUtil.writeTLV(RANGE, sidBuffer, byteAggregator);
232         }
233         if (prefixAtrributes.getSrBindingSidLabels() != null) {
234             BindingSidLabelParser.serializeBindingSidLabels(prefixAtrributes.getSrBindingSidLabels(), byteAggregator, BINDING_SID);
235         }
236     }
237
238     private static void serializeRouteTags(final List<RouteTag> routeTags, final ByteBuf byteAggregator) {
239         if (routeTags != null) {
240             final ByteBuf routeTagsBuf = Unpooled.buffer();
241             for (final RouteTag routeTag : routeTags) {
242                 routeTagsBuf.writeBytes(routeTag.getValue());
243             }
244             TlvUtil.writeTLV(ROUTE_TAG, routeTagsBuf, byteAggregator);
245         }
246     }
247
248     private static void serializeExtendedRouteTags(final List<ExtendedRouteTag> exRouteTags, final ByteBuf byteAggregator) {
249         if (exRouteTags != null) {
250             final ByteBuf extendedBuf = Unpooled.buffer();
251             for (final ExtendedRouteTag exRouteTag : exRouteTags) {
252                 extendedBuf.writeBytes(exRouteTag.getValue());
253             }
254             TlvUtil.writeTLV(EXTENDED_ROUTE_TAG, extendedBuf, byteAggregator);
255         }
256     }
257
258     private static void serializeForwardingAddress(final IpAddress forwardingAddress, final ByteBuf byteAggregator) {
259         if (forwardingAddress != null) {
260             final ByteBuf ospfBuf = Unpooled.buffer();
261             if (forwardingAddress.getIpv4Address() != null) {
262                 ospfBuf.writeBytes(Ipv4Util.bytesForAddress(forwardingAddress.getIpv4Address()));
263             } else if (forwardingAddress.getIpv6Address() != null) {
264                 ospfBuf.writeBytes(Ipv6Util.bytesForAddress(forwardingAddress.getIpv6Address()));
265             }
266             TlvUtil.writeTLV(FORWARDING_ADDRESS, ospfBuf, byteAggregator);
267         }
268     }
269 }