BUG-2571 : created method for serializing FS NLRI to string
[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.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.primitives.UnsignedBytes;
14 import com.google.common.primitives.UnsignedInts;
15 import io.netty.buffer.ByteBuf;
16 import io.netty.buffer.Unpooled;
17 import java.util.ArrayList;
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.BitArray;
23 import org.opendaylight.protocol.util.ByteArray;
24 import org.opendaylight.protocol.util.ByteBufWriteUtil;
25 import org.opendaylight.protocol.util.Ipv4Util;
26 import org.opendaylight.protocol.util.Values;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.BitmaskOperand;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.ComponentType;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.NumericOneByteValue;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.NumericOperand;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.NumericTwoByteValue;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.Flowspec;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.FlowspecBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.FlowspecType;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DestinationPortCase;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DestinationPortCaseBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DestinationPrefixCase;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DestinationPrefixCaseBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DscpCase;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DscpCaseBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.FragmentCase;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.FragmentCaseBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.IcmpCodeCase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.IcmpCodeCaseBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.IcmpTypeCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.IcmpTypeCaseBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.PacketLengthCase;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.PacketLengthCaseBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.PortCase;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.PortCaseBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.ProtocolIpCase;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.ProtocolIpCaseBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.SourcePortCase;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.SourcePortCaseBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.SourcePrefixCase;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.SourcePrefixCaseBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.TcpFlagsCase;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.TcpFlagsCaseBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.destination.port._case.DestinationPorts;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.destination.port._case.DestinationPortsBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.dscp._case.Dscps;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.dscp._case.DscpsBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.fragment._case.Fragments;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.fragment._case.FragmentsBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.icmp.code._case.Codes;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.icmp.code._case.CodesBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.icmp.type._case.Types;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.icmp.type._case.TypesBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.packet.length._case.PacketLengths;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.packet.length._case.PacketLengthsBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.port._case.Ports;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.port._case.PortsBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.protocol.ip._case.ProtocolIps;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.protocol.ip._case.ProtocolIpsBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.source.port._case.SourcePorts;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.source.port._case.SourcePortsBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.tcp.flags._case.TcpFlags;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.tcp.flags._case.TcpFlagsBuilder;
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.DestinationFlowspecCase;
81 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;
82 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;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Attributes;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes1;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlriBuilder;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlri;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlriBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutes;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
92 import org.opendaylight.yangtools.yang.binding.DataObject;
93 import org.opendaylight.yangtools.yang.common.QName;
94 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
95 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
96 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
97 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
98 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
99 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
100 import org.slf4j.Logger;
101 import org.slf4j.LoggerFactory;
102
103 public class FSNlriParser implements NlriParser, NlriSerializer {
104     private static final Logger LOG = LoggerFactory.getLogger(FSNlriParser.class);
105
106     private static final NodeIdentifier FLOWSPEC_TYPE_NID = new NodeIdentifier(FlowspecType.QNAME);
107     @VisibleForTesting
108     static final NodeIdentifier COMPONENT_TYPE_NID = new NodeIdentifier(QName.cachedReference(QName.create(Flowspec.QNAME, "component-type")));
109     @VisibleForTesting
110     static final NodeIdentifier DEST_PREFIX_NID = new NodeIdentifier(QName.cachedReference(QName.create(DestinationPrefixCase.QNAME, "destination-prefix")));
111     private static final NodeIdentifier SOURCE_PREFIX_NID = new NodeIdentifier(QName.cachedReference(QName.create(SourcePrefixCase.QNAME, "source-prefix")));
112     private static final NodeIdentifier PROTOCOL_IP_NID = new NodeIdentifier(ProtocolIps.QNAME);
113     private static final NodeIdentifier PORTS_NID = new NodeIdentifier(Ports.QNAME);
114     private static final NodeIdentifier DEST_PORT_NID = new NodeIdentifier(DestinationPorts.QNAME);
115     private static final NodeIdentifier SOURCE_PORT_NID = new NodeIdentifier(SourcePorts.QNAME);
116     private static final NodeIdentifier ICMP_TYPE_NID = new NodeIdentifier(Types.QNAME);
117     private static final NodeIdentifier ICMP_CODE_NID = new NodeIdentifier(Codes.QNAME);
118     private static final NodeIdentifier TCP_FLAGS_NID = new NodeIdentifier(TcpFlags.QNAME);
119     private static final NodeIdentifier PACKET_LENGTHS_NID = new NodeIdentifier(PacketLengths.QNAME);
120     private static final NodeIdentifier DSCP_NID = new NodeIdentifier(Dscps.QNAME);
121     private static final NodeIdentifier FRAGMENT_NID = new NodeIdentifier(Fragments.QNAME);
122
123     private static final int NLRI_LENGTH = 1;
124     private static final int NLRI_LENGTH_EXTENDED = 2;
125     /**
126      * Add this constant to length value to achieve all ones in the leftmost nibble.
127      */
128     private static final int LENGTH_MAGIC = 61440;
129
130     private static final int OPERAND_LENGTH = 8;
131
132     private static final int END_OF_LIST = 0;
133     private static final int AND_BIT = 1;
134     private static final int LENGTH_BITMASK = 48;
135     private static final int LENGTH_SHIFT = 4;
136     private static final int LESS_THAN = 5;
137     private static final int GREATER_THAN = 6;
138     private static final int EQUAL = 7;
139
140     private static final int NOT = 6;
141     private static final int MATCH = 7;
142
143     private static final int LAST_FRAGMENT = 4;
144     private static final int FIRST_FRAGMENT = 5;
145     private static final int IS_A_FRAGMENT = 6;
146     private static final int DONT_FRAGMENT = 7;
147
148     private static final int MAX_NLRI_LENGTH = 4095;
149     private static final int MAX_NLRI_LENGTH_ONE_BYTE = 240;
150
151     @Override
152     public void serializeAttribute(final DataObject attribute, final ByteBuf byteAggregator) {
153         Preconditions.checkArgument(attribute instanceof Attributes, "Attribute parameter is not a PathAttribute object.");
154         final Attributes pathAttributes = (Attributes) attribute;
155         final Attributes1 pathAttributes1 = pathAttributes.getAugmentation(Attributes1.class);
156         final Attributes2 pathAttributes2 = pathAttributes.getAugmentation(Attributes2.class);
157         if (pathAttributes1 != null) {
158             final AdvertizedRoutes routes = (pathAttributes1.getMpReachNlri()).getAdvertizedRoutes();
159             if (routes != null && routes.getDestinationType() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecCase) {
160                 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 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();
161                 serializeNlri(flowspecCase.getDestinationFlowspec().getFlowspec(), byteAggregator);
162             }
163         } else if (pathAttributes2 != null) {
164             final MpUnreachNlri mpUnreachNlri = pathAttributes2.getMpUnreachNlri();
165             if (mpUnreachNlri.getWithdrawnRoutes() != null && mpUnreachNlri.getWithdrawnRoutes().getDestinationType() instanceof DestinationFlowspecCase) {
166                 final DestinationFlowspecCase flowspecCase = (DestinationFlowspecCase) mpUnreachNlri.getWithdrawnRoutes().getDestinationType();
167                 serializeNlri(flowspecCase.getDestinationFlowspec().getFlowspec(), byteAggregator);
168             }
169         }
170     }
171
172     /**
173      * Serializes Flowspec component type that has maximum of 2B sized value field and numeric operand.
174      *
175      * @param list of items to be serialized
176      * @param nlriByteBuf where the items will be serialized
177      */
178     private static <T extends NumericTwoByteValue> void serializeNumericTwoByteValue(final List<T> list, final ByteBuf nlriByteBuf) {
179         for (final T item : list) {
180             final ByteBuf protoBuf = Unpooled.buffer();
181             writeShortest(item.getValue(), protoBuf);
182             serializeNumericOperand(item.getOp(), protoBuf.readableBytes(), nlriByteBuf);
183             nlriByteBuf.writeBytes(protoBuf);
184         }
185     }
186
187     /**
188      * Serializes Flowspec component type that has maximum of 1B sized value field and numeric operand.
189      *
190      * @param list of items to be serialized
191      * @param nlriByteBuf where the items will be serialized
192      */
193     private static <T extends NumericOneByteValue> void serializeNumericOneByteValue(final List<T> list, final ByteBuf nlriByteBuf) {
194         for (final T type : list) {
195             serializeNumericOperand(type.getOp(), 1, nlriByteBuf);
196             writeShortest(type.getValue(), nlriByteBuf);
197         }
198     }
199
200     /**
201      * Serializes Flowspec NLRI to ByteBuf.
202      *
203      * @param flows flowspec NLRI to be serialized
204      * @param buffer where flowspec NLRI will be serialized
205      */
206     public static void serializeNlri(final List<Flowspec> flows, final ByteBuf buffer) {
207         final ByteBuf nlriByteBuf = Unpooled.buffer();
208         for (final Flowspec flow : flows) {
209             nlriByteBuf.writeByte(flow.getComponentType().getIntValue());
210             final FlowspecType value = flow.getFlowspecType();
211             switch (flow.getComponentType()) {
212             case DestinationPrefix:
213                 nlriByteBuf.writeBytes(Ipv4Util.bytesForPrefixBegin(((DestinationPrefixCase) value).getDestinationPrefix()));
214                 break;
215             case SourcePrefix:
216                 nlriByteBuf.writeBytes(Ipv4Util.bytesForPrefixBegin(((SourcePrefixCase) value).getSourcePrefix()));
217                 break;
218             case ProtocolIp:
219                 serializeNumericTwoByteValue(((ProtocolIpCase) value).getProtocolIps(), nlriByteBuf);
220                 break;
221             case Port:
222                 serializeNumericTwoByteValue(((PortCase) value).getPorts(), nlriByteBuf);
223                 break;
224             case DestinationPort:
225                 serializeNumericTwoByteValue(((DestinationPortCase) value).getDestinationPorts(), nlriByteBuf);
226                 break;
227             case SourcePort:
228                 serializeNumericTwoByteValue(((SourcePortCase) value).getSourcePorts(), nlriByteBuf);
229                 break;
230             case IcmpType:
231                 serializeNumericOneByteValue(((IcmpTypeCase) value).getTypes(), nlriByteBuf);
232                 break;
233             case IcmpCode:
234                 serializeNumericOneByteValue(((IcmpCodeCase) value).getCodes(), nlriByteBuf);
235                 break;
236             case TcpFlags:
237                 final List<TcpFlags> flags = ((TcpFlagsCase) value).getTcpFlags();
238                 for (final TcpFlags flag : flags) {
239                     final ByteBuf flagsBuf = Unpooled.buffer();
240                     writeShortest(flag.getValue(), flagsBuf);
241                     serializeBitmaskOperand(flag.getOp(), flagsBuf.readableBytes(), nlriByteBuf);
242                     nlriByteBuf.writeBytes(flagsBuf);
243                 }
244                 break;
245             case PacketLength:
246                 serializeNumericTwoByteValue(((PacketLengthCase) value).getPacketLengths(), nlriByteBuf);
247                 break;
248             case Dscp:
249                 final List<Dscps> dscps = ((DscpCase) value).getDscps();
250                 for (final Dscps dscp : dscps) {
251                     serializeNumericOperand(dscp.getOp(), 1, nlriByteBuf);
252                     writeShortest(dscp.getValue().getValue(), nlriByteBuf);
253                 }
254                 break;
255             case Fragment:
256                 final List<Fragments> fragments = ((FragmentCase) value).getFragments();
257                 for (final Fragments fragment : fragments) {
258                     serializeBitmaskOperand(fragment.getOp(), 1, nlriByteBuf);
259                     nlriByteBuf.writeByte(serializeFragment(fragment.getValue()));
260                 }
261                 break;
262             default:
263                 LOG.warn("Unknown Component Type.");
264                 break;
265             }
266         }
267         Preconditions.checkState(nlriByteBuf.readableBytes() <= MAX_NLRI_LENGTH, "Maximum length of Flowspec NLRI reached.");
268         if (nlriByteBuf.readableBytes() <= MAX_NLRI_LENGTH_ONE_BYTE) {
269             buffer.writeByte(nlriByteBuf.readableBytes());
270         } else {
271             buffer.writeShort(nlriByteBuf.readableBytes() + LENGTH_MAGIC);
272         }
273         buffer.writeBytes(nlriByteBuf);
274     }
275
276     /**
277      * Given the integer values, this method instead of writing the value
278      * in 4B field, compresses the value to lowest required byte field
279      * depending on the value.
280      *
281      * @param value integer to be written
282      * @param buffer ByteBuf where the value will be written
283      */
284     private static void writeShortest(final int value, final ByteBuf buffer) {
285         if (value <= Values.UNSIGNED_BYTE_MAX_VALUE) {
286             buffer.writeByte(UnsignedBytes.checkedCast(value));
287         } else if (value <= Values.UNSIGNED_SHORT_MAX_VALUE) {
288             ByteBufWriteUtil.writeUnsignedShort(value, buffer);
289         } else if (value <= Values.UNSIGNED_INT_MAX_VALUE) {
290             ByteBufWriteUtil.writeUnsignedInt(UnsignedInts.toLong(value), buffer);
291         } else {
292             buffer.writeLong(value);
293         }
294     }
295
296     private static void serializeNumericOperand(final NumericOperand op, final int length, final ByteBuf buffer) {
297         final BitArray bs = new BitArray(OPERAND_LENGTH);
298         bs.set(END_OF_LIST, op.isEndOfList());
299         bs.set(AND_BIT, op.isAndBit());
300         bs.set(LESS_THAN, op.isLessThan());
301         bs.set(GREATER_THAN, op.isGreaterThan());
302         bs.set(EQUAL, op.isEquals());
303         final byte len = (byte) (Integer.numberOfTrailingZeros(length) << LENGTH_SHIFT);
304         buffer.writeByte(bs.toByte() | len);
305     }
306
307     private static void serializeBitmaskOperand(final BitmaskOperand op, final int length, final ByteBuf buffer) {
308         final BitArray bs = new BitArray(OPERAND_LENGTH);
309         bs.set(END_OF_LIST, op.isEndOfList());
310         bs.set(AND_BIT, op.isAndBit());
311         bs.set(MATCH, op.isMatch());
312         bs.set(NOT, op.isNot());
313         final byte len = (byte) (Integer.numberOfTrailingZeros(length) << LENGTH_SHIFT);
314         buffer.writeByte(bs.toByte() | len);
315     }
316
317     @Override
318     public void parseNlri(final ByteBuf nlri, final MpUnreachNlriBuilder builder) throws BGPParsingException {
319         if (!nlri.isReadable()) {
320             return;
321         }
322         final List<Flowspec> dst = parseNlri(nlri);
323
324         builder.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(
325             new DestinationFlowspecCaseBuilder().setDestinationFlowspec(
326                 new DestinationFlowspecBuilder().setFlowspec(
327                     dst).build()).build()).build());
328     }
329
330     @Override
331     public void parseNlri(final ByteBuf nlri, final MpReachNlriBuilder builder) throws BGPParsingException {
332         if (!nlri.isReadable()) {
333             return;
334         }
335         final List<Flowspec> dst = parseNlri(nlri);
336
337         builder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(
338             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()
339                 .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()
340                     .setFlowspec(dst).build()).build()).build());
341     }
342
343     /**
344      * Parses Flowspec NLRI into list of Flowspec.
345      *
346      * @param nlri byte representation of NLRI which will be parsed
347      * @return list of Flowspec
348      */
349     public static List<Flowspec> parseNlri(final ByteBuf nlri) throws BGPParsingException {
350         if (!nlri.isReadable()) {
351             return null;
352         }
353         final List<Flowspec> fss = new ArrayList<>();
354
355         // length field can be one or two bytes (if needed)
356         // check the length of nlri to see how many bytes we can skip
357         final int length = nlri.readableBytes();
358         nlri.skipBytes(length > MAX_NLRI_LENGTH_ONE_BYTE ? NLRI_LENGTH_EXTENDED : NLRI_LENGTH);
359
360         while (nlri.isReadable()) {
361             final FlowspecBuilder builder = new FlowspecBuilder();
362             // read type
363             final ComponentType type = ComponentType.forValue(nlri.readUnsignedByte());
364             builder.setComponentType(type);
365             switch (type) {
366             case DestinationPrefix:
367                 builder.setFlowspecType(new DestinationPrefixCaseBuilder().setDestinationPrefix(Ipv4Util.prefixForByteBuf(nlri)).build());
368                 break;
369             case SourcePrefix:
370                 builder.setFlowspecType(new SourcePrefixCaseBuilder().setSourcePrefix(Ipv4Util.prefixForByteBuf(nlri)).build());
371                 break;
372             case ProtocolIp:
373                 builder.setFlowspecType(new ProtocolIpCaseBuilder().setProtocolIps(parseProtocolIp(nlri)).build());
374                 break;
375             case Port:
376                 builder.setFlowspecType(new PortCaseBuilder().setPorts(parsePort(nlri)).build());
377                 break;
378             case DestinationPort:
379                 builder.setFlowspecType(new DestinationPortCaseBuilder().setDestinationPorts(parseDestinationPort(nlri)).build());
380                 break;
381             case SourcePort:
382                 builder.setFlowspecType(new SourcePortCaseBuilder().setSourcePorts(parseSourcePort(nlri)).build());
383                 break;
384             case IcmpType:
385                 builder.setFlowspecType(new IcmpTypeCaseBuilder().setTypes(parseIcmpType(nlri)).build());
386                 break;
387             case IcmpCode:
388                 builder.setFlowspecType(new IcmpCodeCaseBuilder().setCodes(parseIcmpCode(nlri)).build());
389                 break;
390             case TcpFlags:
391                 builder.setFlowspecType(new TcpFlagsCaseBuilder().setTcpFlags(parseTcpFlags(nlri)).build());
392                 break;
393             case PacketLength:
394                 builder.setFlowspecType(new PacketLengthCaseBuilder().setPacketLengths(parsePacketLength(nlri)).build());
395                 break;
396             case Dscp:
397                 builder.setFlowspecType(new DscpCaseBuilder().setDscps(parseDscp(nlri)).build());
398                 break;
399             case Fragment:
400                 builder.setFlowspecType(new FragmentCaseBuilder().setFragments(parseFragment(nlri)).build());
401                 break;
402             default:
403                 break;
404             }
405             fss.add(builder.build());
406         }
407         return fss;
408     }
409
410     private static List<ProtocolIps> parseProtocolIp(final ByteBuf nlri) {
411         final List<ProtocolIps> ips = new ArrayList<>();
412         boolean end = false;
413         // we can do this as all fields will be rewritten in the cycle
414         final ProtocolIpsBuilder builder = new ProtocolIpsBuilder();
415         while (!end) {
416             final byte b = nlri.readByte();
417             final NumericOperand op = parseNumeric(b);
418             builder.setOp(op);
419             final short length = parseLength(b);
420             builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
421             end = op.isEndOfList();
422             ips.add(builder.build());
423         }
424         return ips;
425     }
426
427     private static List<Ports> parsePort(final ByteBuf nlri) {
428         final List<Ports> ports = new ArrayList<>();
429         boolean end = false;
430         // we can do this as all fields will be rewritten in the cycle
431         final PortsBuilder builder = new PortsBuilder();
432         while (!end) {
433             final byte b = nlri.readByte();
434             final NumericOperand op = parseNumeric(b);
435             builder.setOp(op);
436             final short length = parseLength(b);
437             builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
438             end = op.isEndOfList();
439             ports.add(builder.build());
440         }
441         return ports;
442     }
443
444     private static List<DestinationPorts> parseDestinationPort(final ByteBuf nlri) {
445         final List<DestinationPorts> ports = new ArrayList<>();
446         boolean end = false;
447         // we can do this as all fields will be rewritten in the cycle
448         final DestinationPortsBuilder builder = new DestinationPortsBuilder();
449         while (!end) {
450             final byte b = nlri.readByte();
451             final NumericOperand op = parseNumeric(b);
452             builder.setOp(op);
453             final short length = parseLength(b);
454             builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
455             end = op.isEndOfList();
456             ports.add(builder.build());
457         }
458         return ports;
459     }
460
461     private static List<SourcePorts> parseSourcePort(final ByteBuf nlri) {
462         final List<SourcePorts> ports = new ArrayList<>();
463         boolean end = false;
464         // we can do this as all fields will be rewritten in the cycle
465         final SourcePortsBuilder builder = new SourcePortsBuilder();
466         while (!end) {
467             final byte b = nlri.readByte();
468             final NumericOperand op = parseNumeric(b);
469             builder.setOp(op);
470             final short length = parseLength(b);
471             builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
472             end = op.isEndOfList();
473             ports.add(builder.build());
474         }
475         return ports;
476     }
477
478     private static List<Types> parseIcmpType(final ByteBuf nlri) {
479         final List<Types> types = new ArrayList<>();
480         boolean end = false;
481         // we can do this as all fields will be rewritten in the cycle
482         final TypesBuilder builder = new TypesBuilder();
483         while (!end) {
484             final byte b = nlri.readByte();
485             final NumericOperand op = parseNumeric(b);
486             builder.setOp(op);
487             builder.setValue(nlri.readUnsignedByte());
488             end = op.isEndOfList();
489             types.add(builder.build());
490         }
491         return types;
492     }
493
494     private static List<Codes> parseIcmpCode(final ByteBuf nlri) {
495         final List<Codes> codes = new ArrayList<>();
496         boolean end = false;
497         // we can do this as all fields will be rewritten in the cycle
498         final CodesBuilder builder = new CodesBuilder();
499         while (!end) {
500             final byte b = nlri.readByte();
501             final NumericOperand op = parseNumeric(b);
502             builder.setOp(op);
503             builder.setValue(nlri.readUnsignedByte());
504             end = op.isEndOfList();
505             codes.add(builder.build());
506         }
507         return codes;
508     }
509
510     private static List<TcpFlags> parseTcpFlags(final ByteBuf nlri) {
511         final List<TcpFlags> flags = new ArrayList<>();
512         boolean end = false;
513         // we can do this as all fields will be rewritten in the cycle
514         final TcpFlagsBuilder builder = new TcpFlagsBuilder();
515         while (!end) {
516             final byte b = nlri.readByte();
517             final BitmaskOperand op = parseBitmask(b);
518             builder.setOp(op);
519             final short length = parseLength(b);
520             builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
521             end = op.isEndOfList();
522             flags.add(builder.build());
523         }
524         return flags;
525     }
526
527     private static List<PacketLengths> parsePacketLength(final ByteBuf nlri) {
528         final List<PacketLengths> plengths = new ArrayList<>();
529         boolean end = false;
530         // we can do this as all fields will be rewritten in the cycle
531         final PacketLengthsBuilder builder = new PacketLengthsBuilder();
532         while (!end) {
533             final byte b = nlri.readByte();
534             // RFC does not specify which operand to use
535             final NumericOperand op = parseNumeric(b);
536             builder.setOp(op);
537             final short length = parseLength(b);
538             builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
539             end = op.isEndOfList();
540             plengths.add(builder.build());
541         }
542         return plengths;
543     }
544
545     private static List<Dscps> parseDscp(final ByteBuf nlri) {
546         final List<Dscps> dscps = new ArrayList<>();
547         boolean end = false;
548         // we can do this as all fields will be rewritten in the cycle
549         final DscpsBuilder builder = new DscpsBuilder();
550         while (!end) {
551             final byte b = nlri.readByte();
552             // RFC does not specify operator
553             final NumericOperand op = parseNumeric(b);
554             builder.setOp(op);
555             builder.setValue(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.Dscp(nlri.readUnsignedByte()));
556             end = op.isEndOfList();
557             dscps.add(builder.build());
558         }
559         return dscps;
560     }
561
562     private static List<Fragments> parseFragment(final ByteBuf nlri) {
563         final List<Fragments> fragments = new ArrayList<>();
564         boolean end = false;
565         // we can do this as all fields will be rewritten in the cycle
566         final FragmentsBuilder builder = new FragmentsBuilder();
567         while (!end) {
568             final byte b = nlri.readByte();
569             final BitmaskOperand op = parseBitmask(b);
570             builder.setOp(op);
571             builder.setValue(parseFragment(nlri.readByte()));
572             end = op.isEndOfList();
573             fragments.add(builder.build());
574         }
575         return fragments;
576     }
577
578     private static NumericOperand parseNumeric(final byte op) {
579         final BitArray bs = BitArray.valueOf(op);
580         return new NumericOperand(bs.get(AND_BIT), bs.get(END_OF_LIST), bs.get(EQUAL), bs.get(GREATER_THAN), bs.get(LESS_THAN));
581     }
582
583     private static BitmaskOperand parseBitmask(final byte op) {
584         final BitArray bs = BitArray.valueOf(op);
585         return new BitmaskOperand(bs.get(AND_BIT), bs.get(END_OF_LIST), bs.get(MATCH), bs.get(NOT));
586     }
587
588     @VisibleForTesting
589     public static short parseLength(final byte op) {
590         return (short) (1 << ((op & LENGTH_BITMASK) >> LENGTH_SHIFT));
591     }
592
593     private static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.Fragment parseFragment(final byte fragment) {
594         final BitArray bs = BitArray.valueOf(fragment);
595         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));
596     }
597
598     private static byte serializeFragment(final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.Fragment fragment) {
599         final BitArray bs = new BitArray(Byte.SIZE);
600         bs.set(DONT_FRAGMENT, fragment.isDoNot());
601         bs.set(FIRST_FRAGMENT, fragment.isFirst());
602         bs.set(IS_A_FRAGMENT, fragment.isIsA());
603         bs.set(LAST_FRAGMENT, fragment.isLast());
604         return bs.toByte();
605     }
606
607     public static String stringNlri(final DataContainerNode<?> flowspec) {
608         return stringNlri(extractFlowspec((MapEntryNode) flowspec));
609     }
610
611     public static Flowspec extractFlowspec(final MapEntryNode route) {
612         final FlowspecBuilder fs = new FlowspecBuilder();
613         final Optional<DataContainerChild<? extends PathArgument, ?>> compType = route.getChild(COMPONENT_TYPE_NID);
614         if (compType.isPresent()) {
615             fs.setComponentType(componentTypeValue((String) compType.get().getValue()));
616         }
617         final ChoiceNode fsType = (ChoiceNode) route.getChild(FLOWSPEC_TYPE_NID).get();
618         if (fsType.getChild(DEST_PREFIX_NID).isPresent()) {
619             fs.setFlowspecType(new DestinationPrefixCaseBuilder().setDestinationPrefix(
620                     new Ipv4Prefix((String) fsType.getChild(DEST_PREFIX_NID).get().getValue())).build());
621         } else if (fsType.getChild(SOURCE_PREFIX_NID).isPresent()) {
622             fs.setFlowspecType(new SourcePrefixCaseBuilder().setSourcePrefix(new Ipv4Prefix((String) fsType.getChild(SOURCE_PREFIX_NID).get().getValue()))
623                     .build());
624         } else if (fsType.getChild(PROTOCOL_IP_NID).isPresent()) {
625             // FIXME: BUG-3044
626             fs.setFlowspecType(new ProtocolIpCaseBuilder().build());
627         } else if (fsType.getChild(PORTS_NID).isPresent()) {
628             // FIXME: BUG-3044
629             fs.setFlowspecType(new PortCaseBuilder().build());
630         } else if (fsType.getChild(DEST_PORT_NID).isPresent()) {
631             // FIXME: BUG-3044
632             fs.setFlowspecType(new DestinationPortCaseBuilder().build());
633         } else if (fsType.getChild(SOURCE_PORT_NID).isPresent()) {
634             // FIXME: BUG-3044
635             fs.setFlowspecType(new SourcePortCaseBuilder().build());
636         } else if (fsType.getChild(ICMP_TYPE_NID).isPresent()) {
637             // FIXME: BUG-3044
638             fs.setFlowspecType(new IcmpTypeCaseBuilder().build());
639         } else if (fsType.getChild(ICMP_CODE_NID).isPresent()) {
640             // FIXME: BUG-3044
641             fs.setFlowspecType(new IcmpCodeCaseBuilder().build());
642         } else if (fsType.getChild(TCP_FLAGS_NID).isPresent()) {
643             // FIXME: BUG-3044
644             fs.setFlowspecType(new TcpFlagsCaseBuilder().build());
645         } else if (fsType.getChild(PACKET_LENGTHS_NID).isPresent()) {
646             // FIXME: BUG-3044
647             fs.setFlowspecType(new PacketLengthCaseBuilder().build());
648         } else if (fsType.getChild(DSCP_NID).isPresent()) {
649             // FIXME: BUG-3044
650             fs.setFlowspecType(new DscpCaseBuilder().build());
651         } else if (fsType.getChild(FRAGMENT_NID).isPresent()) {
652             // FIXME: BUG-3044
653             fs.setFlowspecType(new FragmentCaseBuilder().build());
654         }
655         return fs.build();
656     }
657
658     // FIXME: use codec
659     private static ComponentType componentTypeValue(final String compType) {
660         switch (compType) {
661         case "destination-prefix":
662             return ComponentType.DestinationPrefix;
663         case "source-prefix":
664             return ComponentType.SourcePrefix;
665         case "protocol-ip":
666             return ComponentType.ProtocolIp;
667         case "port":
668             return ComponentType.Port;
669         case "destination-port":
670             return ComponentType.DestinationPort;
671         case "source-port":
672             return ComponentType.SourcePort;
673         case "icmp-type":
674             return ComponentType.IcmpType;
675         case "icmp-code":
676             return ComponentType.IcmpCode;
677         case "tcp-flags":
678             return ComponentType.TcpFlags;
679         case "packet-length":
680             return ComponentType.PacketLength;
681         case "dscp":
682             return ComponentType.Dscp;
683         case "fragment":
684             return ComponentType.Fragment;
685         default:
686             return null;
687         }
688     }
689
690     @VisibleForTesting
691     static final String stringNlri(final Flowspec flow) {
692         final StringBuilder buffer = new StringBuilder("all packets ");
693         final FlowspecType value = flow.getFlowspecType();
694         switch (flow.getComponentType()) {
695         case DestinationPrefix:
696             buffer.append("to ");
697             buffer.append(((DestinationPrefixCase) value).getDestinationPrefix().getValue());
698             break;
699         case SourcePrefix:
700             buffer.append("from ");
701             buffer.append(((SourcePrefixCase) value).getSourcePrefix().getValue());
702             break;
703         case ProtocolIp:
704             buffer.append("where protocol ");
705             buffer.append(stringNumericTwo(((ProtocolIpCase) value).getProtocolIps()));
706             break;
707         case Port:
708             buffer.append("where port ");
709             buffer.append(stringNumericTwo(((PortCase) value).getPorts()));
710             break;
711         case DestinationPort:
712             buffer.append("where destination port ");
713             buffer.append(stringNumericTwo(((DestinationPortCase) value).getDestinationPorts()));
714             break;
715         case SourcePort:
716             buffer.append("where source port ");
717             buffer.append(stringNumericTwo(((SourcePortCase) value).getSourcePorts()));
718             break;
719         case IcmpType:
720             buffer.append("where ICMP type ");
721             buffer.append(stringNumericOne(((IcmpTypeCase) value).getTypes()));
722             break;
723         case IcmpCode:
724             buffer.append("where ICMP code ");
725             buffer.append(stringNumericOne(((IcmpCodeCase) value).getCodes()));
726             break;
727         case TcpFlags:
728             buffer.append(stringTcpFlags(((TcpFlagsCase) value).getTcpFlags()));
729             break;
730         case PacketLength:
731             buffer.append("where packet length ");
732             buffer.append(stringNumericTwo(((PacketLengthCase) value).getPacketLengths()));
733             break;
734         case Dscp:
735             buffer.append(stringDscp(((DscpCase) value).getDscps()));
736             break;
737         case Fragment:
738             buffer.append(stringFragment(((FragmentCase) value).getFragments()));
739             break;
740         default:
741             LOG.warn("Skipping unhandled component type {}" , flow.getComponentType());
742             break;
743         }
744         return buffer.toString();
745     }
746
747     private static <T extends NumericTwoByteValue> String stringNumericTwo(final List<T> list) {
748         final StringBuilder buffer = new StringBuilder();
749         boolean isFirst = true;
750         for (final T item : list) {
751             buffer.append(stringNumericOperand(item.getOp(), isFirst));
752             buffer.append(item.getValue());
753             buffer.append(' ');
754             if (isFirst) {
755                 isFirst = false;
756             }
757         }
758         return buffer.toString();
759     }
760
761     private static <T extends NumericOneByteValue> String stringNumericOne(final List<T> list) {
762         final StringBuilder buffer = new StringBuilder();
763         boolean isFirst = true;
764         for (final T item : list) {
765             buffer.append(stringNumericOperand(item.getOp(), isFirst));
766             buffer.append(item.getValue());
767             buffer.append(' ');
768             if (isFirst) {
769                 isFirst = false;
770             }
771         }
772         return buffer.toString();
773     }
774
775     private static String stringNumericOperand(final NumericOperand op, final boolean isFirst) {
776         final StringBuilder buffer = new StringBuilder();
777         if (!op.isAndBit() && !isFirst) {
778             buffer.append("or ");
779         }
780         if (op.isAndBit()) {
781             buffer.append("and ");
782         }
783         if (op.isLessThan() && op.isEquals()) {
784             buffer.append("is less than or equal to ");
785             return buffer.toString();
786         } else if (op.isGreaterThan() && op.isEquals()) {
787             buffer.append("is greater than or equal to ");
788             return buffer.toString();
789         }
790         if (op.isEquals()) {
791             buffer.append("equals to ");
792         }
793         if (op.isLessThan()) {
794             buffer.append("is less than ");
795         }
796         if (op.isGreaterThan()) {
797             buffer.append("is greater than ");
798         }
799         return buffer.toString();
800     }
801
802     private static String stringTcpFlags(final List<TcpFlags> flags) {
803         final StringBuilder buffer = new StringBuilder("where TCP flags ");
804         boolean isFirst = true;
805         for (final TcpFlags item : flags) {
806             buffer.append(stringBitmaskOperand(item.getOp(), isFirst));
807             buffer.append(item.getValue());
808             buffer.append(' ');
809             if (isFirst) {
810                 isFirst = false;
811             }
812         }
813         return buffer.toString();
814     }
815
816     private static String stringBitmaskOperand(final BitmaskOperand op, final boolean isFirst) {
817         final StringBuilder buffer = new StringBuilder();
818         if (!op.isAndBit() && !isFirst) {
819             buffer.append("or ");
820         }
821         if (op.isAndBit()) {
822             buffer.append("and ");
823         }
824         if (op.isMatch()) {
825             buffer.append("does ");
826             if (op.isNot()) {
827                 buffer.append("not ");
828             }
829             buffer.append("match ");
830         } else if (op.isNot()) {
831             buffer.append("is not ");
832         }
833         return buffer.toString();
834     }
835
836     private static String stringDscp(final List<Dscps> dscps) {
837         final StringBuilder buffer = new StringBuilder("where DSCP ");
838         boolean isFirst = true;
839         for (final Dscps item : dscps) {
840             buffer.append(stringNumericOperand(item.getOp(), isFirst));
841             buffer.append(item.getValue().getValue());
842             buffer.append(' ');
843             if (isFirst) {
844                 isFirst = false;
845             }
846         }
847         return buffer.toString();
848     }
849
850     private static String stringFragment(final List<Fragments> fragments) {
851         final StringBuilder buffer = new StringBuilder("where fragment ");
852         boolean isFirst = true;
853         for (final Fragments item : fragments) {
854             buffer.append(stringBitmaskOperand(item.getOp(), isFirst));
855             buffer.append(stringFragment(item.getValue()));
856             if (isFirst) {
857                 isFirst = false;
858             }
859         }
860         return buffer.toString();
861     }
862
863     private static String stringFragment(final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.Fragment fragment) {
864         final StringBuilder buffer = new StringBuilder();
865         if (fragment.isDoNot()) {
866             buffer.append("'DO NOT' ");
867         }
868         if (fragment.isFirst()) {
869             buffer.append("'IS FIRST' ");
870         }
871         if (fragment.isLast()) {
872             buffer.append("'IS LAST' ");
873         }
874         if (fragment.isIsA()) {
875             buffer.append("'IS A' ");
876         }
877         return buffer.toString();
878     }
879 }