Merge "BUG-2712: do not hold lock while updating future"
[bgpcep.git] / bgp / flowspec / src / main / java / org / opendaylight / protocol / bgp / flowspec / FSNlriParser.java
1 /*
2  * Copyright (c) 2015 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.flowspec;
9
10 import com.google.common.annotations.VisibleForTesting;
11 import com.google.common.base.Preconditions;
12 import com.google.common.primitives.UnsignedBytes;
13 import com.google.common.primitives.UnsignedInts;
14 import io.netty.buffer.ByteBuf;
15 import io.netty.buffer.Unpooled;
16 import java.util.ArrayList;
17 import java.util.BitSet;
18 import java.util.List;
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.protocol.util.ByteArray;
23 import org.opendaylight.protocol.util.ByteBufWriteUtil;
24 import org.opendaylight.protocol.util.Ipv4Util;
25 import org.opendaylight.protocol.util.Values;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.BitmaskOperand;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.ComponentType;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.NumericOneByteValue;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.NumericOperand;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.NumericTwoByteValue;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.Flowspec;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.FlowspecBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.FlowspecType;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DestinationPortCase;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DestinationPortCaseBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DestinationPrefixCase;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DestinationPrefixCaseBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DscpCase;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DscpCaseBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.FragmentCase;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.FragmentCaseBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.IcmpCodeCase;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.IcmpCodeCaseBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.IcmpTypeCase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.IcmpTypeCaseBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.PacketLengthCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.PacketLengthCaseBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.PortCase;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.PortCaseBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.ProtocolIpCase;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.ProtocolIpCaseBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.SourcePortCase;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.SourcePortCaseBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.SourcePrefixCase;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.SourcePrefixCaseBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.TcpFlagsCase;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.TcpFlagsCaseBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.destination.port._case.DestinationPorts;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.destination.port._case.DestinationPortsBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.dscp._case.Dscps;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.dscp._case.DscpsBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.fragment._case.Fragments;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.fragment._case.FragmentsBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.icmp.code._case.Codes;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.icmp.code._case.CodesBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.icmp.type._case.Types;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.icmp.type._case.TypesBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.packet.length._case.PacketLengths;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.packet.length._case.PacketLengthsBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.port._case.Ports;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.port._case.PortsBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.protocol.ip._case.ProtocolIps;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.protocol.ip._case.ProtocolIpsBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.source.port._case.SourcePorts;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.source.port._case.SourcePortsBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.tcp.flags._case.TcpFlags;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.tcp.flags._case.TcpFlagsBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationFlowspecCase;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationFlowspecCaseBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.destination.flowspec._case.DestinationFlowspecBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributes;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes1;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes2;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlriBuilder;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlri;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlriBuilder;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.reach.nlri.AdvertizedRoutes;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
90 import org.opendaylight.yangtools.yang.binding.DataObject;
91 import org.slf4j.Logger;
92 import org.slf4j.LoggerFactory;
93
94 public class FSNlriParser implements NlriParser, NlriSerializer {
95     private static final Logger LOG = LoggerFactory.getLogger(FSNlriParser.class);
96
97     private static final int NLRI_LENGTH = 1;
98     private static final int NLRI_LENGTH_EXTENDED = 2;
99     /**
100      * Add this constant to length value to achieve all ones in the leftmost nibble.
101      */
102     private static final int LENGTH_MAGIC = 61440;
103
104     private static final int END_OF_LIST = 7;
105     private static final int AND_BIT = 6;
106     private static final int LENGTH_BITMASK = 48;
107     private static final int LENGTH_SHIFT = 4;
108     private static final int LESS_THAN = 2;
109     private static final int GREATER_THAN = 1;
110     private static final int EQUAL = 0;
111
112     private static final int NOT = 1;
113     private static final int MATCH = 0;
114
115     private static final int LAST_FRAGMENT = 7;
116     private static final int FIRST_FRAGMENT = 6;
117     private static final int IS_A_FRAGMENT = 5;
118     private static final int DONT_FRAGMENT = 4;
119
120     private static final int MAX_NLRI_LENGTH = 4095;
121     private static final int MAX_NLRI_LENGTH_ONE_BYTE = 240;
122
123     @Override
124     public void serializeAttribute(final DataObject attribute, final ByteBuf byteAggregator) {
125         Preconditions.checkArgument(attribute instanceof PathAttributes, "Attribute parameter is not a PathAttribute object.");
126         final PathAttributes pathAttributes = (PathAttributes) attribute;
127         final PathAttributes1 pathAttributes1 = pathAttributes.getAugmentation(PathAttributes1.class);
128         final PathAttributes2 pathAttributes2 = pathAttributes.getAugmentation(PathAttributes2.class);
129         if (pathAttributes1 != null) {
130             final AdvertizedRoutes routes = (pathAttributes1.getMpReachNlri()).getAdvertizedRoutes();
131             if (routes != null &&
132                 routes.getDestinationType()
133                 instanceof
134                 org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecCase) {
135                 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecCase
136                 flowspecCase = (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecCase) routes.getDestinationType();
137                 serializeNlri(flowspecCase.getDestinationFlowspec().getFlowspec(), byteAggregator);
138             }
139         } else if (pathAttributes2 != null) {
140             final MpUnreachNlri mpUnreachNlri = pathAttributes2.getMpUnreachNlri();
141             if (mpUnreachNlri.getWithdrawnRoutes() != null && mpUnreachNlri.getWithdrawnRoutes().getDestinationType() instanceof DestinationFlowspecCase) {
142                 final DestinationFlowspecCase flowspecCase = (DestinationFlowspecCase) mpUnreachNlri.getWithdrawnRoutes().getDestinationType();
143                 serializeNlri(flowspecCase.getDestinationFlowspec().getFlowspec(), byteAggregator);
144             }
145         }
146     }
147
148     /**
149      * Serializes Flowspec component type that has maximum of 2B sized value field and numeric operand.
150      *
151      * @param list of items to be serialized
152      * @param nlriByteBuf where the items will be serialized
153      */
154     private static <T extends NumericTwoByteValue> void serializeNumericTwoByteValue(final List<T> list, final ByteBuf nlriByteBuf) {
155         for (final T item : list) {
156             final ByteBuf protoBuf = Unpooled.buffer();
157             writeShortest(item.getValue(), protoBuf);
158             serializeNumericOperand(item.getOp(), protoBuf.readableBytes(), nlriByteBuf);
159             nlriByteBuf.writeBytes(protoBuf);
160         }
161     }
162
163     /**
164      * Serializes Flowspec component type that has maximum of 1B sized value field and numeric operand.
165      *
166      * @param list of items to be serialized
167      * @param nlriByteBuf where the items will be serialized
168      */
169     private static <T extends NumericOneByteValue> void serializeNumericOneByteValue(final List<T> list, final ByteBuf nlriByteBuf) {
170         for (final T type : list) {
171             serializeNumericOperand(type.getOp(), 1, nlriByteBuf);
172             writeShortest(type.getValue(), nlriByteBuf);
173         }
174     }
175
176     /**
177      * Serializes Flowspec NLRI to ByteBuf.
178      *
179      * @param flow flowspec NLRI to be serialized
180      */
181     public static void serializeNlri(final List<Flowspec> flows, final ByteBuf buffer) {
182         final ByteBuf nlriByteBuf = Unpooled.buffer();
183         for (final Flowspec flow : flows) {
184             nlriByteBuf.writeByte(flow.getComponentType().getIntValue());
185             final FlowspecType value = flow.getFlowspecType();
186             switch (flow.getComponentType()) {
187             case DestinationPrefix:
188                 nlriByteBuf.writeBytes(Ipv4Util.bytesForPrefixBegin(((DestinationPrefixCase)value).getDestinationPrefix()));
189                 break;
190             case SourcePrefix:
191                 nlriByteBuf.writeBytes(Ipv4Util.bytesForPrefixBegin(((SourcePrefixCase)value).getSourcePrefix()));
192                 break;
193             case ProtocolIp:
194                 serializeNumericTwoByteValue(((ProtocolIpCase)value).getProtocolIps(), nlriByteBuf);
195                 break;
196             case Port:
197                 serializeNumericTwoByteValue(((PortCase)value).getPorts(), nlriByteBuf);
198                 break;
199             case DestinationPort:
200                 serializeNumericTwoByteValue(((DestinationPortCase)value).getDestinationPorts(), nlriByteBuf);
201                 break;
202             case SourcePort:
203                 serializeNumericTwoByteValue(((SourcePortCase)value).getSourcePorts(), nlriByteBuf);
204                 break;
205             case IcmpType:
206                 serializeNumericOneByteValue(((IcmpTypeCase)value).getTypes(), nlriByteBuf);
207                 break;
208             case IcmpCode:
209                 serializeNumericOneByteValue(((IcmpCodeCase)value).getCodes(), nlriByteBuf);
210                 break;
211             case TcpFlags:
212                 final List<TcpFlags> flags = ((TcpFlagsCase)value).getTcpFlags();
213                 for (final TcpFlags flag : flags) {
214                     final ByteBuf flagsBuf = Unpooled.buffer();
215                     writeShortest(flag.getValue(), flagsBuf);
216                     serializeBitmaskOperand(flag.getOp(), flagsBuf.readableBytes(), nlriByteBuf);
217                     nlriByteBuf.writeBytes(flagsBuf);
218                 }
219                 break;
220             case PacketLength:
221                 serializeNumericTwoByteValue(((PacketLengthCase)value).getPacketLengths(), nlriByteBuf);
222                 break;
223             case Dscp:
224                 final List<Dscps> dscps = ((DscpCase)value).getDscps();
225                 for (final Dscps dscp : dscps) {
226                     serializeNumericOperand(dscp.getOp(), 1, nlriByteBuf);
227                     writeShortest(dscp.getValue().getValue(), nlriByteBuf);
228                 }
229                 break;
230             case Fragment:
231                 final List<Fragments> fragments = ((FragmentCase)value).getFragments();
232                 for (final Fragments fragment : fragments) {
233                     serializeBitmaskOperand(fragment.getOp(), 1, nlriByteBuf);
234                     nlriByteBuf.writeByte(serializeFragment(fragment.getValue()));
235                 }
236                 break;
237             default:
238                 LOG.warn("Unknown Component Type.");
239                 break;
240             }
241         }
242         Preconditions.checkState(nlriByteBuf.readableBytes() <= MAX_NLRI_LENGTH, "Maximum length of Flowspec NLRI reached.");
243         if (nlriByteBuf.readableBytes() <= MAX_NLRI_LENGTH_ONE_BYTE) {
244             buffer.writeByte(nlriByteBuf.readableBytes());
245         } else {
246             buffer.writeShort(nlriByteBuf.readableBytes() + LENGTH_MAGIC);
247         }
248         buffer.writeBytes(nlriByteBuf);
249     }
250
251     /**
252      * Given the integer values, this method instead of writing the value
253      * in 4B field, compresses the value to lowest required byte field
254      * depending on the value.
255      *
256      * @param value integer to be written
257      * @param buffer ByteBuf where the value will be written
258      */
259     private static void writeShortest(final int value, final ByteBuf buffer) {
260         if (value <= Values.UNSIGNED_BYTE_MAX_VALUE) {
261             buffer.writeByte(UnsignedBytes.checkedCast(value));
262         } else if (value <= Values.UNSIGNED_SHORT_MAX_VALUE) {
263             ByteBufWriteUtil.writeUnsignedShort(value, buffer);
264         } else if (value <= Values.UNSIGNED_INT_MAX_VALUE) {
265             ByteBufWriteUtil.writeUnsignedInt(UnsignedInts.toLong(value), buffer);
266         } else {
267             buffer.writeLong(value);
268         }
269     }
270
271     private static void serializeNumericOperand(final NumericOperand op, final int length, final ByteBuf buffer) {
272         final BitSet bs = new BitSet(Byte.SIZE);
273         if (op.isEndOfList() != null) {
274             bs.set(END_OF_LIST, op.isEndOfList());
275         }
276         if (op.isAndBit() != null) {
277             bs.set(AND_BIT, op.isAndBit());
278         }
279         if (op.isLessThan() != null) {
280             bs.set(LESS_THAN, op.isLessThan());
281         }
282         if (op.isGreaterThan() != null) {
283             bs.set(GREATER_THAN, op.isGreaterThan());
284         }
285         if (op.isEquals() != null) {
286             bs.set(EQUAL, op.isEquals());
287         }
288         final byte len = (byte) (Integer.numberOfTrailingZeros(length) << LENGTH_SHIFT);
289         buffer.writeByte(bs.toByteArray()[0] | len);
290     }
291
292     private static void serializeBitmaskOperand(final BitmaskOperand op, final int length, final ByteBuf buffer) {
293         final BitSet bs = new BitSet(Byte.SIZE);
294         if (op.isEndOfList() != null) {
295             bs.set(END_OF_LIST, op.isEndOfList());
296         }
297         if (op.isAndBit() != null) {
298             bs.set(AND_BIT, op.isAndBit());
299         }
300         if (op.isMatch() != null) {
301             bs.set(MATCH, op.isMatch());
302         }
303         if (op.isNot() != null) {
304             bs.set(NOT, op.isNot());
305         }
306         final byte len = (byte) (Integer.numberOfTrailingZeros(length) << LENGTH_SHIFT);
307         buffer.writeByte(bs.toByteArray()[0] | len);
308     }
309
310     @Override
311     public void parseNlri(final ByteBuf nlri, final MpUnreachNlriBuilder builder) throws BGPParsingException {
312         if (!nlri.isReadable()) {
313             return;
314         }
315         final List<Flowspec> dst = parseNlri(nlri);
316
317         builder.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(
318             new DestinationFlowspecCaseBuilder().setDestinationFlowspec(
319                 new DestinationFlowspecBuilder().setFlowspec(
320                     dst).build()).build()).build());
321     }
322
323     @Override
324     public void parseNlri(final ByteBuf nlri, final MpReachNlriBuilder builder) throws BGPParsingException {
325         if (!nlri.isReadable()) {
326             return;
327         }
328         final List<Flowspec> dst = parseNlri(nlri);
329
330         builder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(
331             new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecCaseBuilder()
332                 .setDestinationFlowspec(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.destination.flowspec._case.DestinationFlowspecBuilder().setFlowspec(dst).build()).build()).build());
333     }
334
335     public static List<Flowspec> parseNlri(final ByteBuf nlri) throws BGPParsingException {
336         if (!nlri.isReadable()) {
337             return null;
338         }
339         final List<Flowspec> fss = new ArrayList<>();
340
341         // length field can be one or two bytes (if needed)
342         // check the length of nlri to see how many bytes we can skip
343         final int length = nlri.readableBytes();
344         nlri.skipBytes(length > MAX_NLRI_LENGTH_ONE_BYTE ? NLRI_LENGTH_EXTENDED : NLRI_LENGTH);
345
346         while(nlri.isReadable()) {
347             final FlowspecBuilder builder = new FlowspecBuilder();
348             // read type
349             final ComponentType type = ComponentType.forValue(nlri.readUnsignedByte());
350             builder.setComponentType(type);
351             switch (type) {
352             case DestinationPrefix:
353                 builder.setFlowspecType(new DestinationPrefixCaseBuilder().setDestinationPrefix(Ipv4Util.prefixForByteBuf(nlri)).build());
354                 break;
355             case SourcePrefix:
356                 builder.setFlowspecType(new SourcePrefixCaseBuilder().setSourcePrefix(Ipv4Util.prefixForByteBuf(nlri)).build());
357                 break;
358             case ProtocolIp:
359                 builder.setFlowspecType(new ProtocolIpCaseBuilder().setProtocolIps(parseProtocolIp(nlri)).build());
360                 break;
361             case Port:
362                 builder.setFlowspecType(new PortCaseBuilder().setPorts(parsePort(nlri)).build());
363                 break;
364             case DestinationPort:
365                 builder.setFlowspecType(new DestinationPortCaseBuilder().setDestinationPorts(parseDestinationPort(nlri)).build());
366                 break;
367             case SourcePort:
368                 builder.setFlowspecType(new SourcePortCaseBuilder().setSourcePorts(parseSourcePort(nlri)).build());
369                 break;
370             case IcmpType:
371                 builder.setFlowspecType(new IcmpTypeCaseBuilder().setTypes(parseIcmpType(nlri)).build());
372                 break;
373             case IcmpCode:
374                 builder.setFlowspecType(new IcmpCodeCaseBuilder().setCodes(parseIcmpCode(nlri)).build());
375                 break;
376             case TcpFlags:
377                 builder.setFlowspecType(new TcpFlagsCaseBuilder().setTcpFlags(parseTcpFlags(nlri)).build());
378                 break;
379             case PacketLength:
380                 builder.setFlowspecType(new PacketLengthCaseBuilder().setPacketLengths(parsePacketLength(nlri)).build());
381                 break;
382             case Dscp:
383                 builder.setFlowspecType(new DscpCaseBuilder().setDscps(parseDscp(nlri)).build());
384                 break;
385             case Fragment:
386                 builder.setFlowspecType(new FragmentCaseBuilder().setFragments(parseFragment(nlri)).build());
387                 break;
388             default:
389                 break;
390             }
391             fss.add(builder.build());
392         }
393         return fss;
394     }
395
396     private static List<ProtocolIps> parseProtocolIp(final ByteBuf nlri) {
397         final List<ProtocolIps> ips = new ArrayList<>();
398         boolean end = false;
399         // we can do this as all fields will be rewritten in the cycle
400         final ProtocolIpsBuilder builder = new ProtocolIpsBuilder();
401         while (!end) {
402             final byte b = nlri.readByte();
403             final NumericOperand op = parseNumeric(b);
404             builder.setOp(op);
405             final short length = parseLength(b);
406             builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
407             end = op.isEndOfList();
408             ips.add(builder.build());
409         }
410         return ips;
411     }
412
413     private static List<Ports> parsePort(final ByteBuf nlri) {
414         final List<Ports> ports = new ArrayList<>();
415         boolean end = false;
416         // we can do this as all fields will be rewritten in the cycle
417         final PortsBuilder builder = new PortsBuilder();
418         while (!end) {
419             final byte b = nlri.readByte();
420             final NumericOperand op = parseNumeric(b);
421             builder.setOp(op);
422             final short length = parseLength(b);
423             builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
424             end = op.isEndOfList();
425             ports.add(builder.build());
426         }
427         return ports;
428     }
429
430     private static List<DestinationPorts> parseDestinationPort(final ByteBuf nlri) {
431         final List<DestinationPorts> ports = new ArrayList<>();
432         boolean end = false;
433         // we can do this as all fields will be rewritten in the cycle
434         final DestinationPortsBuilder builder = new DestinationPortsBuilder();
435         while (!end) {
436             final byte b = nlri.readByte();
437             final NumericOperand op = parseNumeric(b);
438             builder.setOp(op);
439             final short length = parseLength(b);
440             builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
441             end = op.isEndOfList();
442             ports.add(builder.build());
443         }
444         return ports;
445     }
446
447     private static List<SourcePorts> parseSourcePort(final ByteBuf nlri) {
448         final List<SourcePorts> ports = new ArrayList<>();
449         boolean end = false;
450         // we can do this as all fields will be rewritten in the cycle
451         final SourcePortsBuilder builder = new SourcePortsBuilder();
452         while (!end) {
453             final byte b = nlri.readByte();
454             final NumericOperand op = parseNumeric(b);
455             builder.setOp(op);
456             final short length = parseLength(b);
457             builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
458             end = op.isEndOfList();
459             ports.add(builder.build());
460         }
461         return ports;
462     }
463
464     private static List<Types> parseIcmpType(final ByteBuf nlri) {
465         final List<Types> types = new ArrayList<>();
466         boolean end = false;
467         // we can do this as all fields will be rewritten in the cycle
468         final TypesBuilder builder = new TypesBuilder();
469         while (!end) {
470             final byte b = nlri.readByte();
471             final NumericOperand op = parseNumeric(b);
472             builder.setOp(op);
473             builder.setValue(nlri.readUnsignedByte());
474             end = op.isEndOfList();
475             types.add(builder.build());
476         }
477         return types;
478     }
479
480     private static List<Codes> parseIcmpCode(final ByteBuf nlri) {
481         final List<Codes> codes = new ArrayList<>();
482         boolean end = false;
483         // we can do this as all fields will be rewritten in the cycle
484         final CodesBuilder builder = new CodesBuilder();
485         while (!end) {
486             final byte b = nlri.readByte();
487             final NumericOperand op = parseNumeric(b);
488             builder.setOp(op);
489             builder.setValue(nlri.readUnsignedByte());
490             end = op.isEndOfList();
491             codes.add(builder.build());
492         }
493         return codes;
494     }
495
496     private static List<TcpFlags> parseTcpFlags(final ByteBuf nlri) {
497         final List<TcpFlags> flags = new ArrayList<>();
498         boolean end = false;
499         // we can do this as all fields will be rewritten in the cycle
500         final TcpFlagsBuilder builder = new TcpFlagsBuilder();
501         while (!end) {
502             final byte b = nlri.readByte();
503             final BitmaskOperand op = parseBitmask(b);
504             builder.setOp(op);
505             final short length = parseLength(b);
506             builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
507             end = op.isEndOfList();
508             flags.add(builder.build());
509         }
510         return flags;
511     }
512
513     private static List<PacketLengths> parsePacketLength(final ByteBuf nlri) {
514         final List<PacketLengths> plengths = new ArrayList<>();
515         boolean end = false;
516         // we can do this as all fields will be rewritten in the cycle
517         final PacketLengthsBuilder builder = new PacketLengthsBuilder();
518         while (!end) {
519             final byte b = nlri.readByte();
520             // RFC does not specify which operand to use
521             final NumericOperand op = parseNumeric(b);
522             builder.setOp(op);
523             final short length = parseLength(b);
524             builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
525             end = op.isEndOfList();
526             plengths.add(builder.build());
527         }
528         return plengths;
529     }
530
531     private static List<Dscps> parseDscp(final ByteBuf nlri) {
532         final List<Dscps> dscps = new ArrayList<>();
533         boolean end = false;
534         // we can do this as all fields will be rewritten in the cycle
535         final DscpsBuilder builder = new DscpsBuilder();
536         while (!end) {
537             final byte b = nlri.readByte();
538             // RFC does not specify operator
539             final NumericOperand op = parseNumeric(b);
540             builder.setOp(op);
541             builder.setValue(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.Dscp(nlri.readUnsignedByte()));
542             end = op.isEndOfList();
543             dscps.add(builder.build());
544         }
545         return dscps;
546     }
547
548     private static List<Fragments> parseFragment(final ByteBuf nlri) {
549         final List<Fragments> fragments = new ArrayList<>();
550         boolean end = false;
551         // we can do this as all fields will be rewritten in the cycle
552         final FragmentsBuilder builder = new FragmentsBuilder();
553         while (!end) {
554             final byte b = nlri.readByte();
555             final BitmaskOperand op = parseBitmask(b);
556             builder.setOp(op);
557             builder.setValue(parseFragment(nlri.readByte()));
558             end = op.isEndOfList();
559             fragments.add(builder.build());
560         }
561         return fragments;
562     }
563
564     private static NumericOperand parseNumeric(final byte op) {
565         final BitSet bs = BitSet.valueOf(new long[] {UnsignedBytes.toInt(op)});
566         return new NumericOperand(bs.get(AND_BIT), bs.get(END_OF_LIST), bs.get(EQUAL), bs.get(GREATER_THAN), bs.get(LESS_THAN));
567     }
568
569     private static BitmaskOperand parseBitmask(final byte op) {
570         final BitSet bs = BitSet.valueOf(new long[] {UnsignedBytes.toInt(op)});
571         return new BitmaskOperand(bs.get(AND_BIT), bs.get(END_OF_LIST), bs.get(MATCH), bs.get(NOT));
572     }
573
574     @VisibleForTesting
575     public static short parseLength(final byte op) {
576         return (short) (1 << ((op & LENGTH_BITMASK) >> LENGTH_SHIFT));
577     }
578
579     private static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.Fragment parseFragment(final byte fragment) {
580         final BitSet bs = BitSet.valueOf(new long[] {UnsignedBytes.toInt(fragment)});
581         return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.Fragment(bs.get(DONT_FRAGMENT), bs.get(FIRST_FRAGMENT), bs.get(IS_A_FRAGMENT), bs.get(LAST_FRAGMENT));
582     }
583
584     private static byte serializeFragment(final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.Fragment fragment) {
585         final BitSet bs = new BitSet(Byte.SIZE);
586         if (fragment.isDoNot() != null) {
587             bs.set(DONT_FRAGMENT, fragment.isDoNot());
588         }
589         if (fragment.isFirst() != null) {
590             bs.set(FIRST_FRAGMENT, fragment.isFirst());
591         }
592         if (fragment.isIsA() != null) {
593             bs.set(IS_A_FRAGMENT, fragment.isIsA());
594         }
595         if (fragment.isLast() != null) {
596             bs.set(LAST_FRAGMENT, fragment.isLast());
597         }
598         return bs.toByteArray()[0];
599     }
600 }