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