2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.protocol.bgp.flowspec;
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;
20 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
21 import org.opendaylight.protocol.bgp.parser.spi.NlriParser;
22 import org.opendaylight.protocol.bgp.parser.spi.NlriSerializer;
23 import org.opendaylight.protocol.util.BitArray;
24 import org.opendaylight.protocol.util.ByteArray;
25 import org.opendaylight.protocol.util.ByteBufWriteUtil;
26 import org.opendaylight.protocol.util.Values;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.BitmaskOperand;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.Dscp;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.Fragment;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.NumericOneByteValue;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.NumericOperand;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.NumericTwoByteValue;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.Flowspec;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.FlowspecBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.FlowspecType;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.DestinationPortCase;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.DestinationPortCaseBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.DscpCase;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.DscpCaseBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.FragmentCase;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.FragmentCaseBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.IcmpCodeCase;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.IcmpCodeCaseBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.IcmpTypeCase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.IcmpTypeCaseBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.PacketLengthCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.PacketLengthCaseBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.PortCase;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.PortCaseBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.SourcePortCase;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.SourcePortCaseBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.TcpFlagsCase;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.TcpFlagsCaseBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.destination.port._case.DestinationPorts;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.destination.port._case.DestinationPortsBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.dscp._case.Dscps;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.dscp._case.DscpsBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.fragment._case.Fragments;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.fragment._case.FragmentsBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.icmp.code._case.Codes;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.icmp.code._case.CodesBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.icmp.type._case.Types;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.icmp.type._case.TypesBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.packet.length._case.PacketLengths;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.packet.length._case.PacketLengthsBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.port._case.Ports;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.port._case.PortsBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.source.port._case.SourcePorts;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.source.port._case.SourcePortsBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.tcp.flags._case.TcpFlags;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.flowspec.flowspec.type.tcp.flags._case.TcpFlagsBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.ipv4.flowspec.flowspec.type.DestinationPrefixCase;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.flowspec.destination.ipv4.flowspec.flowspec.type.SourcePrefixCase;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Attributes;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes1;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.destination.DestinationType;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlriBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlriBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
82 import org.opendaylight.yangtools.yang.binding.DataObject;
83 import org.opendaylight.yangtools.yang.common.QName;
84 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
85 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
86 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
87 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
88 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
89 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
90 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
91 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
93 public abstract class AbstractFSNlriParser implements NlriParser, NlriSerializer {
95 // component types values
96 protected static final int DESTINATION_PREFIX_VALUE = 1;
97 protected static final int SOURCE_PREFIX_VALUE = 2;
98 protected static final int PORT_VALUE = 4;
99 protected static final int DESTINATION_PORT_VALUE = 5;
100 protected static final int SOURCE_PORT_VALUE = 6;
101 protected static final int ICMP_TYPE_VALUE = 7;
102 protected static final int ICMP_CODE_VALUE = 8;
103 protected static final int TCP_FLAGS_VALUE = 9;
104 protected static final int PACKET_LENGTH_VALUE = 10;
105 protected static final int DSCP_VALUE = 11;
106 protected static final int FRAGMENT_VALUE = 12;
108 protected static final NodeIdentifier FLOWSPEC_TYPE_NID = new NodeIdentifier(FlowspecType.QNAME);
110 static final NodeIdentifier DEST_PREFIX_NID = new NodeIdentifier(QName.cachedReference(QName.create(DestinationPrefixCase.QNAME, "destination-prefix")));
112 static final NodeIdentifier SOURCE_PREFIX_NID = new NodeIdentifier(QName.cachedReference(QName.create(SourcePrefixCase.QNAME, "source-prefix")));
114 static final NodeIdentifier PORTS_NID = new NodeIdentifier(Ports.QNAME);
116 static final NodeIdentifier DEST_PORT_NID = new NodeIdentifier(DestinationPorts.QNAME);
118 static final NodeIdentifier SOURCE_PORT_NID = new NodeIdentifier(SourcePorts.QNAME);
120 static final NodeIdentifier ICMP_TYPE_NID = new NodeIdentifier(Types.QNAME);
122 static final NodeIdentifier ICMP_CODE_NID = new NodeIdentifier(Codes.QNAME);
124 static final NodeIdentifier TCP_FLAGS_NID = new NodeIdentifier(TcpFlags.QNAME);
126 static final NodeIdentifier PACKET_LENGTHS_NID = new NodeIdentifier(PacketLengths.QNAME);
128 static final NodeIdentifier DSCP_NID = new NodeIdentifier(Dscps.QNAME);
130 static final NodeIdentifier FRAGMENT_NID = new NodeIdentifier(Fragments.QNAME);
132 static final NodeIdentifier OP_NID = new NodeIdentifier(QName.create("urn:opendaylight:params:xml:ns:yang:bgp-flowspec","2015-08-07","op"));
134 static final NodeIdentifier VALUE_NID = new NodeIdentifier(QName.create("urn:opendaylight:params:xml:ns:yang:bgp-flowspec","2015-08-07","value"));
136 protected static final int NLRI_LENGTH = 1;
137 protected static final int NLRI_LENGTH_EXTENDED = 2;
139 private static final int OPERAND_LENGTH = 8;
141 private static final int END_OF_LIST = 0;
142 private static final int AND_BIT = 1;
143 private static final int LENGTH_BITMASK = 48;
144 private static final int LENGTH_SHIFT = 4;
145 private static final int LESS_THAN = 5;
146 private static final int GREATER_THAN = 6;
147 private static final int EQUAL = 7;
148 private static final int NOT = 6;
149 private static final int MATCH = 7;
152 * Add this constant to length value to achieve all ones in the leftmost nibble.
154 private static final int LENGTH_MAGIC = 61440;
155 private static final int MAX_NLRI_LENGTH = 4095;
156 private static final int MAX_NLRI_LENGTH_ONE_BYTE = 240;
159 static final String AND_BIT_VALUE = "and-bit";
161 static final String END_OF_LIST_VALUE = "end-of-list";
163 static final String EQUALS_VALUE = "equals";
165 static final String GREATER_THAN_VALUE = "greater-than";
167 static final String LESS_THAN_VALUE = "less-than";
169 static final String MATCH_VALUE = "match";
171 static final String NOT_VALUE = "not";
173 static final String DO_NOT_VALUE = "do-not";
175 static final String FIRST_VALUE = "first";
177 static final String LAST_VALUE = "last";
179 static final String IS_A_VALUE = "is-a";
181 protected static final int LAST_FRAGMENT = 4;
182 protected static final int FIRST_FRAGMENT = 5;
183 protected static final int IS_A_FRAGMENT = 6;
184 protected static final int DONT_FRAGMENT = 7;
186 protected abstract void serializeMpReachNlri(final Attributes1 pathAttributes, final ByteBuf byteAggregator);
188 protected abstract void serializeMpUnreachNlri(final Attributes2 pathAttributes, final ByteBuf byteAggregator);
190 protected abstract void serializeSpecificFSType(final FlowspecType fsType, final ByteBuf nlriByteBuf);
192 protected abstract byte serializeFragment(final Fragment fragment);
194 protected abstract Fragment parseFragment(final byte fragment);
196 protected abstract void setSpecificFlowspecType(final FlowspecBuilder builder, final short type, final ByteBuf nlri);
198 public abstract void extractSpecificFlowspec(final ChoiceNode fsType, final FlowspecBuilder fsBuilder);
200 abstract DestinationType createWidthdrawnDestinationType(final List<Flowspec> dst);
202 abstract DestinationType createAdvertizedRoutesDestinationType(final List<Flowspec> dst);
204 protected abstract void stringSpecificFSNlriType(final FlowspecType value, final StringBuilder buffer);
207 public final void serializeAttribute(final DataObject attribute, final ByteBuf byteAggregator) {
208 Preconditions.checkArgument(attribute instanceof Attributes, "Attribute parameter is not a PathAttribute object.");
209 final Attributes pathAttributes = (Attributes) attribute;
210 final Attributes1 pathAttributes1 = pathAttributes.getAugmentation(Attributes1.class);
211 final Attributes2 pathAttributes2 = pathAttributes.getAugmentation(Attributes2.class);
212 serializeMpReachNlri(pathAttributes1, byteAggregator);
213 serializeMpUnreachNlri(pathAttributes2, byteAggregator);
217 public final void parseNlri(final ByteBuf nlri, final MpUnreachNlriBuilder builder) throws BGPParsingException {
218 if (!nlri.isReadable()) {
221 final List<Flowspec> dst = parseNlri(nlri);
223 builder.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(createWidthdrawnDestinationType(dst)).build());
227 public final void parseNlri(final ByteBuf nlri, final MpReachNlriBuilder builder) throws BGPParsingException {
228 if (!nlri.isReadable()) {
231 final List<Flowspec> dst = parseNlri(nlri);
232 builder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(createAdvertizedRoutesDestinationType(dst)).build());
236 * Serializes Flowspec NLRI to ByteBuf.
238 * @param flows flowspec NLRI to be serialized
239 * @param buffer where flowspec NLRI will be serialized
241 public final void serializeNlri(final List<Flowspec> flows, final ByteBuf buffer) {
242 final ByteBuf nlriByteBuf = Unpooled.buffer();
243 for (final Flowspec flow : flows) {
244 serializeFlowspec(flow, nlriByteBuf);
246 Preconditions.checkState(nlriByteBuf.readableBytes() <= MAX_NLRI_LENGTH, "Maximum length of Flowspec NLRI reached.");
247 if (nlriByteBuf.readableBytes() <= MAX_NLRI_LENGTH_ONE_BYTE) {
248 buffer.writeByte(nlriByteBuf.readableBytes());
250 buffer.writeShort(nlriByteBuf.readableBytes() + LENGTH_MAGIC);
252 buffer.writeBytes(nlriByteBuf);
256 * Serializes Flowspec component type that has maximum of 2B sized value field and numeric operand.
258 * @param list of items to be serialized
259 * @param nlriByteBuf where the items will be serialized
261 protected static final <T extends NumericTwoByteValue> void serializeNumericTwoByteValue(final List<T> list, final ByteBuf nlriByteBuf) {
262 for (final T item : list) {
263 final ByteBuf protoBuf = Unpooled.buffer();
264 writeShortest(item.getValue(), protoBuf);
265 serializeNumericOperand(item.getOp(), protoBuf.readableBytes(), nlriByteBuf);
266 nlriByteBuf.writeBytes(protoBuf);
271 * Serializes Flowspec component type that has maximum of 1B sized value field and numeric operand.
273 * @param list of items to be serialized
274 * @param nlriByteBuf where the items will be serialized
276 protected static final <T extends NumericOneByteValue> void serializeNumericOneByteValue(final List<T> list, final ByteBuf nlriByteBuf) {
277 for (final T type : list) {
278 serializeNumericOperand(type.getOp(), 1, nlriByteBuf);
279 writeShortest(type.getValue(), nlriByteBuf);
284 * Given the integer values, this method instead of writing the value
285 * in 4B field, compresses the value to lowest required byte field
286 * depending on the value.
288 * @param value integer to be written
289 * @param buffer ByteBuf where the value will be written
291 protected static final void writeShortest(final int value, final ByteBuf buffer) {
292 if (value <= Values.UNSIGNED_BYTE_MAX_VALUE) {
293 buffer.writeByte(UnsignedBytes.checkedCast(value));
294 } else if (value <= Values.UNSIGNED_SHORT_MAX_VALUE) {
295 ByteBufWriteUtil.writeUnsignedShort(value, buffer);
296 } else if (value <= Values.UNSIGNED_INT_MAX_VALUE) {
297 ByteBufWriteUtil.writeUnsignedInt(UnsignedInts.toLong(value), buffer);
299 buffer.writeLong(value);
303 protected static final void serializeNumericOperand(final NumericOperand op, final int length, final ByteBuf buffer) {
304 final BitArray bs = new BitArray(OPERAND_LENGTH);
305 bs.set(END_OF_LIST, op.isEndOfList());
306 bs.set(AND_BIT, op.isAndBit());
307 bs.set(LESS_THAN, op.isLessThan());
308 bs.set(GREATER_THAN, op.isGreaterThan());
309 bs.set(EQUAL, op.isEquals());
310 final byte len = (byte) (Integer.numberOfTrailingZeros(length) << LENGTH_SHIFT);
311 buffer.writeByte(bs.toByte() | len);
314 protected static final void serializeBitmaskOperand(final BitmaskOperand op, final int length, final ByteBuf buffer) {
315 final BitArray bs = new BitArray(OPERAND_LENGTH);
316 bs.set(END_OF_LIST, op.isEndOfList());
317 bs.set(AND_BIT, op.isAndBit());
318 bs.set(MATCH, op.isMatch());
319 bs.set(NOT, op.isNot());
320 final byte len = (byte) (Integer.numberOfTrailingZeros(length) << LENGTH_SHIFT);
321 buffer.writeByte(bs.toByte() | len);
324 protected static final void serializeTcpFlags(final List<TcpFlags> flags, final ByteBuf nlriByteBuf) {
325 for (final TcpFlags flag : flags) {
326 final ByteBuf flagsBuf = Unpooled.buffer();
327 writeShortest(flag.getValue(), flagsBuf);
328 serializeBitmaskOperand(flag.getOp(), flagsBuf.readableBytes(), nlriByteBuf);
329 nlriByteBuf.writeBytes(flagsBuf);
333 protected static final void serializeDscps(final List<Dscps> dscps, final ByteBuf nlriByteBuf) {
334 for (final Dscps dscp : dscps) {
335 serializeNumericOperand(dscp.getOp(), 1, nlriByteBuf);
336 writeShortest(dscp.getValue().getValue(), nlriByteBuf);
340 protected final void serializeFragments(final List<Fragments> fragments, final ByteBuf nlriByteBuf) {
341 for (final Fragments fragment : fragments) {
342 serializeBitmaskOperand(fragment.getOp(), 1, nlriByteBuf);
343 nlriByteBuf.writeByte(serializeFragment(fragment.getValue()));
347 protected final void serializeFlowspec(final Flowspec flow, final ByteBuf nlriByteBuf) {
348 final FlowspecType fsType = flow.getFlowspecType();
349 if (fsType instanceof PortCase) {
350 nlriByteBuf.writeByte(PORT_VALUE);
351 serializeNumericTwoByteValue(((PortCase) fsType).getPorts(), nlriByteBuf);
352 } else if (fsType instanceof DestinationPortCase) {
353 nlriByteBuf.writeByte(DESTINATION_PORT_VALUE);
354 serializeNumericTwoByteValue(((DestinationPortCase) fsType).getDestinationPorts(), nlriByteBuf);
355 } else if (fsType instanceof SourcePortCase) {
356 nlriByteBuf.writeByte(SOURCE_PORT_VALUE);
357 serializeNumericTwoByteValue(((SourcePortCase) fsType).getSourcePorts(), nlriByteBuf);
358 } else if (fsType instanceof IcmpTypeCase) {
359 nlriByteBuf.writeByte(ICMP_TYPE_VALUE);
360 serializeNumericOneByteValue(((IcmpTypeCase) fsType).getTypes(), nlriByteBuf);
361 } else if (fsType instanceof IcmpCodeCase) {
362 nlriByteBuf.writeByte(ICMP_CODE_VALUE);
363 serializeNumericOneByteValue(((IcmpCodeCase) fsType).getCodes(), nlriByteBuf);
364 } else if (fsType instanceof TcpFlagsCase) {
365 nlriByteBuf.writeByte(TCP_FLAGS_VALUE);
366 serializeTcpFlags(((TcpFlagsCase) fsType).getTcpFlags(), nlriByteBuf);
367 } else if (fsType instanceof PacketLengthCase) {
368 nlriByteBuf.writeByte(PACKET_LENGTH_VALUE);
369 serializeNumericTwoByteValue(((PacketLengthCase) fsType).getPacketLengths(), nlriByteBuf);
370 } else if (fsType instanceof DscpCase) {
371 nlriByteBuf.writeByte(DSCP_VALUE);
372 serializeDscps(((DscpCase) fsType).getDscps(), nlriByteBuf);
374 serializeSpecificFSType(fsType, nlriByteBuf);
379 * Parses Flowspec NLRI into list of Flowspec.
381 * @param nlri byte representation of NLRI which will be parsed
382 * @return list of Flowspec
384 public final List<Flowspec> parseNlri(final ByteBuf nlri) throws BGPParsingException {
385 if (!nlri.isReadable()) {
388 final List<Flowspec> fss = new ArrayList<>();
390 // length field can be one or two bytes (if needed)
391 // check the length of nlri to see how many bytes we can skip
392 final int length = nlri.readableBytes();
393 nlri.skipBytes(length > MAX_NLRI_LENGTH_ONE_BYTE ? NLRI_LENGTH_EXTENDED : NLRI_LENGTH);
395 while (nlri.isReadable()) {
396 final FlowspecBuilder builder = new FlowspecBuilder();
397 final short type = nlri.readUnsignedByte();
398 setFlowspecType(builder, type, nlri);
399 fss.add(builder.build());
404 protected final void setFlowspecType(final FlowspecBuilder builder, final short type, final ByteBuf nlri) {
407 builder.setFlowspecType(new PortCaseBuilder().setPorts(parsePort(nlri)).build());
409 case DESTINATION_PORT_VALUE:
410 builder.setFlowspecType(new DestinationPortCaseBuilder().setDestinationPorts(parseDestinationPort(nlri)).build());
412 case SOURCE_PORT_VALUE:
413 builder.setFlowspecType(new SourcePortCaseBuilder().setSourcePorts(parseSourcePort(nlri)).build());
415 case ICMP_TYPE_VALUE:
416 builder.setFlowspecType(new IcmpTypeCaseBuilder().setTypes(parseIcmpType(nlri)).build());
418 case ICMP_CODE_VALUE:
419 builder.setFlowspecType(new IcmpCodeCaseBuilder().setCodes(parseIcmpCode(nlri)).build());
421 case TCP_FLAGS_VALUE:
422 builder.setFlowspecType(new TcpFlagsCaseBuilder().setTcpFlags(parseTcpFlags(nlri)).build());
424 case PACKET_LENGTH_VALUE:
425 builder.setFlowspecType(new PacketLengthCaseBuilder().setPacketLengths(parsePacketLength(nlri)).build());
428 builder.setFlowspecType(new DscpCaseBuilder().setDscps(parseDscp(nlri)).build());
431 setSpecificFlowspecType(builder, type, nlri);
436 private static List<Ports> parsePort(final ByteBuf nlri) {
437 final List<Ports> ports = new ArrayList<>();
439 // we can do this as all fields will be rewritten in the cycle
440 final PortsBuilder builder = new PortsBuilder();
442 final byte b = nlri.readByte();
443 final NumericOperand op = parseNumeric(b);
445 final short length = parseLength(b);
446 builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
447 end = op.isEndOfList();
448 ports.add(builder.build());
453 private static List<DestinationPorts> parseDestinationPort(final ByteBuf nlri) {
454 final List<DestinationPorts> ports = new ArrayList<>();
456 // we can do this as all fields will be rewritten in the cycle
457 final DestinationPortsBuilder builder = new DestinationPortsBuilder();
459 final byte b = nlri.readByte();
460 final NumericOperand op = parseNumeric(b);
462 final short length = parseLength(b);
463 builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
464 end = op.isEndOfList();
465 ports.add(builder.build());
470 private static List<SourcePorts> parseSourcePort(final ByteBuf nlri) {
471 final List<SourcePorts> ports = new ArrayList<>();
473 // we can do this as all fields will be rewritten in the cycle
474 final SourcePortsBuilder builder = new SourcePortsBuilder();
476 final byte b = nlri.readByte();
477 final NumericOperand op = parseNumeric(b);
479 final short length = parseLength(b);
480 builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
481 end = op.isEndOfList();
482 ports.add(builder.build());
487 private static List<Types> parseIcmpType(final ByteBuf nlri) {
488 final List<Types> types = new ArrayList<>();
490 // we can do this as all fields will be rewritten in the cycle
491 final TypesBuilder builder = new TypesBuilder();
493 final byte b = nlri.readByte();
494 final NumericOperand op = parseNumeric(b);
496 builder.setValue(nlri.readUnsignedByte());
497 end = op.isEndOfList();
498 types.add(builder.build());
503 private static List<Codes> parseIcmpCode(final ByteBuf nlri) {
504 final List<Codes> codes = new ArrayList<>();
506 // we can do this as all fields will be rewritten in the cycle
507 final CodesBuilder builder = new CodesBuilder();
509 final byte b = nlri.readByte();
510 final NumericOperand op = parseNumeric(b);
512 builder.setValue(nlri.readUnsignedByte());
513 end = op.isEndOfList();
514 codes.add(builder.build());
519 private static List<TcpFlags> parseTcpFlags(final ByteBuf nlri) {
520 final List<TcpFlags> flags = new ArrayList<>();
522 // we can do this as all fields will be rewritten in the cycle
523 final TcpFlagsBuilder builder = new TcpFlagsBuilder();
525 final byte b = nlri.readByte();
526 final BitmaskOperand op = parseBitmask(b);
528 final short length = parseLength(b);
529 builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
530 end = op.isEndOfList();
531 flags.add(builder.build());
536 private static List<PacketLengths> parsePacketLength(final ByteBuf nlri) {
537 final List<PacketLengths> plengths = new ArrayList<>();
539 // we can do this as all fields will be rewritten in the cycle
540 final PacketLengthsBuilder builder = new PacketLengthsBuilder();
542 final byte b = nlri.readByte();
543 // RFC does not specify which operand to use
544 final NumericOperand op = parseNumeric(b);
546 final short length = parseLength(b);
547 builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
548 end = op.isEndOfList();
549 plengths.add(builder.build());
554 private static List<Dscps> parseDscp(final ByteBuf nlri) {
555 final List<Dscps> dscps = new ArrayList<>();
557 // we can do this as all fields will be rewritten in the cycle
558 final DscpsBuilder builder = new DscpsBuilder();
560 final byte b = nlri.readByte();
561 // RFC does not specify operator
562 final NumericOperand op = parseNumeric(b);
564 builder.setValue(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150807.Dscp(nlri.readUnsignedByte()));
565 end = op.isEndOfList();
566 dscps.add(builder.build());
571 protected final List<Fragments> parseFragment(final ByteBuf nlri) {
572 final List<Fragments> fragments = new ArrayList<>();
574 // we can do this as all fields will be rewritten in the cycle
575 final FragmentsBuilder builder = new FragmentsBuilder();
577 final byte b = nlri.readByte();
578 final BitmaskOperand op = parseBitmask(b);
580 builder.setValue(parseFragment(nlri.readByte()));
581 end = op.isEndOfList();
582 fragments.add(builder.build());
587 protected static final NumericOperand parseNumeric(final byte op) {
588 final BitArray bs = BitArray.valueOf(op);
589 return new NumericOperand(bs.get(AND_BIT), bs.get(END_OF_LIST), bs.get(EQUAL), bs.get(GREATER_THAN), bs.get(LESS_THAN));
592 protected static final BitmaskOperand parseBitmask(final byte op) {
593 final BitArray bs = BitArray.valueOf(op);
594 return new BitmaskOperand(bs.get(AND_BIT), bs.get(END_OF_LIST), bs.get(MATCH), bs.get(NOT));
598 public static final short parseLength(final byte op) {
599 return (short) (1 << ((op & LENGTH_BITMASK) >> LENGTH_SHIFT));
602 public final String stringNlri(final DataContainerNode<?> flowspec) {
603 return stringNlri(extractFlowspec((MapEntryNode) flowspec));
606 public final Flowspec extractFlowspec(final MapEntryNode route) {
607 final FlowspecBuilder fsBuilder = new FlowspecBuilder();
608 final Optional<DataContainerChild<?, ?>> flowspecType = route.getChild(FLOWSPEC_TYPE_NID);
609 if (flowspecType.isPresent()) {
610 final ChoiceNode fsType = (ChoiceNode) flowspecType.get();
611 if (fsType.getChild(PORTS_NID).isPresent()) {
612 fsBuilder.setFlowspecType(new PortCaseBuilder().setPorts(createPorts((UnkeyedListNode) fsType.getChild(PORTS_NID).get())).build());
613 } else if (fsType.getChild(DEST_PORT_NID).isPresent()) {
614 fsBuilder.setFlowspecType(new DestinationPortCaseBuilder().setDestinationPorts(createDestinationPorts((UnkeyedListNode) fsType.getChild(DEST_PORT_NID).get())).build());
615 } else if (fsType.getChild(SOURCE_PORT_NID).isPresent()) {
616 fsBuilder.setFlowspecType(new SourcePortCaseBuilder().setSourcePorts(createSourcePorts((UnkeyedListNode) fsType.getChild(SOURCE_PORT_NID).get())).build());
617 } else if (fsType.getChild(ICMP_TYPE_NID).isPresent()) {
618 fsBuilder.setFlowspecType(new IcmpTypeCaseBuilder().setTypes(createTypes((UnkeyedListNode) fsType.getChild(ICMP_TYPE_NID).get())).build());
619 } else if (fsType.getChild(ICMP_CODE_NID).isPresent()) {
620 fsBuilder.setFlowspecType(new IcmpCodeCaseBuilder().setCodes(createCodes((UnkeyedListNode) fsType.getChild(ICMP_CODE_NID).get())).build());
621 } else if (fsType.getChild(TCP_FLAGS_NID).isPresent()) {
622 fsBuilder.setFlowspecType(new TcpFlagsCaseBuilder().setTcpFlags(createTcpFlags((UnkeyedListNode) fsType.getChild(TCP_FLAGS_NID).get())).build());
623 } else if (fsType.getChild(PACKET_LENGTHS_NID).isPresent()) {
624 fsBuilder.setFlowspecType(new PacketLengthCaseBuilder().setPacketLengths(createPacketLengths((UnkeyedListNode) fsType.getChild(PACKET_LENGTHS_NID).get())).build());
625 } else if (fsType.getChild(DSCP_NID).isPresent()) {
626 fsBuilder.setFlowspecType(new DscpCaseBuilder().setDscps(createDscpsLengths((UnkeyedListNode) fsType.getChild(DSCP_NID).get())).build());
627 } else if (fsType.getChild(FRAGMENT_NID).isPresent()) {
628 fsBuilder.setFlowspecType(new FragmentCaseBuilder().setFragments(createFragments((UnkeyedListNode) fsType.getChild(FRAGMENT_NID).get())).build());
630 extractSpecificFlowspec(fsType, fsBuilder);
633 return fsBuilder.build();
636 private static List<Ports> createPorts(final UnkeyedListNode portsData) {
637 final List<Ports> ports = new ArrayList<>();
639 for (final UnkeyedListEntryNode node : portsData.getValue()) {
640 final PortsBuilder portsBuilder = new PortsBuilder();
641 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
642 if (opValue.isPresent()) {
643 portsBuilder.setOp(createNumericOperand((Set<String>) opValue.get().getValue()));
645 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
646 if (valueNode.isPresent()) {
647 portsBuilder.setValue((Integer) valueNode.get().getValue());
649 ports.add(portsBuilder.build());
655 private static List<DestinationPorts> createDestinationPorts(final UnkeyedListNode destinationPortsData) {
656 final List<DestinationPorts> destinationPorts = new ArrayList<>();
658 for (final UnkeyedListEntryNode node : destinationPortsData.getValue()) {
659 final DestinationPortsBuilder destPortsBuilder = new DestinationPortsBuilder();
660 if (node.getNodeType().getLocalName().equals("op")) {
661 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
662 if (opValue.isPresent()) {
663 destPortsBuilder.setOp(createNumericOperand((Set<String>) opValue.get().getValue()));
666 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
667 if (valueNode.isPresent()) {
668 destPortsBuilder.setValue((Integer) valueNode.get().getValue());
670 destinationPorts.add(destPortsBuilder.build());
673 return destinationPorts;
676 private static List<SourcePorts> createSourcePorts(final UnkeyedListNode sourcePortsData) {
677 final List<SourcePorts> sourcePorts = new ArrayList<>();
679 for (final UnkeyedListEntryNode node : sourcePortsData.getValue()) {
680 final SourcePortsBuilder sourcePortsBuilder = new SourcePortsBuilder();
681 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
682 if (opValue.isPresent()) {
683 sourcePortsBuilder.setOp(createNumericOperand((Set<String>) opValue.get().getValue()));
685 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
686 if (valueNode.isPresent()) {
687 sourcePortsBuilder.setValue((Integer) valueNode.get().getValue());
689 sourcePorts.add(sourcePortsBuilder.build());
695 private static List<Types> createTypes(final UnkeyedListNode typesData) {
696 final List<Types> types = new ArrayList<>();
698 for (final UnkeyedListEntryNode node : typesData.getValue()) {
699 final TypesBuilder typesBuilder = new TypesBuilder();
700 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
701 if (opValue.isPresent()) {
702 typesBuilder.setOp(createNumericOperand((Set<String>) opValue.get().getValue()));
704 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
705 if (valueNode.isPresent()) {
706 typesBuilder.setValue((Short) valueNode.get().getValue());
708 types.add(typesBuilder.build());
714 private static List<Codes> createCodes(final UnkeyedListNode codesData) {
715 final List<Codes> codes = new ArrayList<>();
717 for (final UnkeyedListEntryNode node : codesData.getValue()) {
718 final CodesBuilder codesBuilder = new CodesBuilder();
719 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
720 if (opValue.isPresent()) {
721 codesBuilder.setOp(createNumericOperand((Set<String>) opValue.get().getValue()));
723 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
724 if (valueNode.isPresent()) {
725 codesBuilder.setValue((Short) valueNode.get().getValue());
727 codes.add(codesBuilder.build());
733 private static List<TcpFlags> createTcpFlags(final UnkeyedListNode tcpFlagsData) {
734 final List<TcpFlags> tcpFlags = new ArrayList<>();
736 for (final UnkeyedListEntryNode node : tcpFlagsData.getValue()) {
737 final TcpFlagsBuilder tcpFlagsBuilder = new TcpFlagsBuilder();
738 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
739 if (opValue.isPresent()) {
740 tcpFlagsBuilder.setOp(createBitmaskOperand((Set<String>) opValue.get().getValue()));
742 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
743 if (valueNode.isPresent()) {
744 tcpFlagsBuilder.setValue((Integer) valueNode.get().getValue());
746 tcpFlags.add(tcpFlagsBuilder.build());
752 private static List<PacketLengths> createPacketLengths(final UnkeyedListNode packetLengthsData) {
753 final List<PacketLengths> packetLengths = new ArrayList<>();
755 for (final UnkeyedListEntryNode node : packetLengthsData.getValue()) {
756 final PacketLengthsBuilder packetLengthsBuilder = new PacketLengthsBuilder();
757 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
758 if (opValue.isPresent()) {
759 packetLengthsBuilder.setOp(createNumericOperand((Set<String>) opValue.get().getValue()));
761 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
762 if (valueNode.isPresent()) {
763 packetLengthsBuilder.setValue((Integer) valueNode.get().getValue());
765 packetLengths.add(packetLengthsBuilder.build());
768 return packetLengths;
771 private static List<Dscps> createDscpsLengths(final UnkeyedListNode dscpLengthsData) {
772 final List<Dscps> dscpsLengths = new ArrayList<>();
774 for (final UnkeyedListEntryNode node : dscpLengthsData.getValue()) {
775 final DscpsBuilder dscpsLengthsBuilder = new DscpsBuilder();
776 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
777 if (opValue.isPresent()) {
778 dscpsLengthsBuilder.setOp(createNumericOperand((Set<String>) opValue.get().getValue()));
780 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
781 if (valueNode.isPresent()) {
782 dscpsLengthsBuilder.setValue(new Dscp((Short) valueNode.get().getValue()));
784 dscpsLengths.add(dscpsLengthsBuilder.build());
790 private static List<Fragments> createFragments(final UnkeyedListNode fragmentsData) {
791 final List<Fragments> fragments = new ArrayList<>();
793 for (final UnkeyedListEntryNode node : fragmentsData.getValue()) {
794 final FragmentsBuilder fragmentsBuilder = new FragmentsBuilder();
795 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
796 if (opValue.isPresent()) {
797 fragmentsBuilder.setOp(createBitmaskOperand((Set<String>) opValue.get().getValue()));
799 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
800 if (valueNode.isPresent()) {
801 fragmentsBuilder.setValue(createFragment((Set<String>) valueNode.get().getValue()));
803 fragments.add(fragmentsBuilder.build());
809 private static Fragment createFragment(final Set<String> data) {
810 return new Fragment(data.contains(DO_NOT_VALUE), data.contains(FIRST_VALUE), data.contains(IS_A_VALUE), data.contains(LAST_VALUE));
813 protected static final NumericOperand createNumericOperand(final Set<String> opValues) {
814 return new NumericOperand(opValues.contains(AND_BIT_VALUE), opValues.contains(END_OF_LIST_VALUE), opValues.contains(EQUALS_VALUE), opValues.contains(GREATER_THAN_VALUE), opValues.contains(LESS_THAN_VALUE));
817 private static BitmaskOperand createBitmaskOperand(final Set<String> opValues) {
818 return new BitmaskOperand(opValues.contains(AND_BIT_VALUE), opValues.contains(END_OF_LIST_VALUE), opValues.contains(MATCH_VALUE), opValues.contains(NOT_VALUE));
822 final String stringNlri(final Flowspec flow) {
823 final StringBuilder buffer = new StringBuilder("all packets ");
824 final FlowspecType value = flow.getFlowspecType();
825 if (value instanceof PortCase) {
826 buffer.append("where port ");
827 buffer.append(stringNumericTwo(((PortCase) value).getPorts()));
828 } else if (value instanceof DestinationPortCase) {
829 buffer.append("where destination port ");
830 buffer.append(stringNumericTwo(((DestinationPortCase) value).getDestinationPorts()));
831 } else if (value instanceof SourcePortCase) {
832 buffer.append("where source port ");
833 buffer.append(stringNumericTwo(((SourcePortCase) value).getSourcePorts()));
834 } else if (value instanceof IcmpTypeCase) {
835 buffer.append("where ICMP type ");
836 buffer.append(stringNumericOne(((IcmpTypeCase) value).getTypes()));
837 } else if (value instanceof IcmpCodeCase) {
838 buffer.append("where ICMP code ");
839 buffer.append(stringNumericOne(((IcmpCodeCase) value).getCodes()));
840 } else if (value instanceof TcpFlagsCase) {
841 buffer.append(stringTcpFlags(((TcpFlagsCase) value).getTcpFlags()));
842 } else if (value instanceof PacketLengthCase) {
843 buffer.append("where packet length ");
844 buffer.append(stringNumericTwo(((PacketLengthCase) value).getPacketLengths()));
845 } else if (value instanceof DscpCase) {
846 buffer.append(stringDscp(((DscpCase) value).getDscps()));
847 } else if (value instanceof FragmentCase) {
848 buffer.append(stringFragment(((FragmentCase) value).getFragments()));
850 stringSpecificFSNlriType(value, buffer);
852 return buffer.toString();
855 private static <T extends NumericTwoByteValue> String stringNumericTwo(final List<T> list) {
856 final StringBuilder buffer = new StringBuilder();
857 boolean isFirst = true;
858 for (final T item : list) {
859 buffer.append(stringNumericOperand(item.getOp(), isFirst));
860 buffer.append(item.getValue());
866 return buffer.toString();
869 protected static final <T extends NumericOneByteValue> String stringNumericOne(final List<T> list) {
870 final StringBuilder buffer = new StringBuilder();
871 boolean isFirst = true;
872 for (final T item : list) {
873 buffer.append(stringNumericOperand(item.getOp(), isFirst));
874 buffer.append(item.getValue());
880 return buffer.toString();
883 protected static final String stringNumericOperand(final NumericOperand op, final boolean isFirst) {
884 final StringBuilder buffer = new StringBuilder();
885 if (!op.isAndBit() && !isFirst) {
886 buffer.append("or ");
889 buffer.append("and ");
891 if (op.isLessThan() && op.isEquals()) {
892 buffer.append("is less than or equal to ");
893 return buffer.toString();
894 } else if (op.isGreaterThan() && op.isEquals()) {
895 buffer.append("is greater than or equal to ");
896 return buffer.toString();
899 buffer.append("equals to ");
901 if (op.isLessThan()) {
902 buffer.append("is less than ");
904 if (op.isGreaterThan()) {
905 buffer.append("is greater than ");
907 return buffer.toString();
910 private static String stringTcpFlags(final List<TcpFlags> flags) {
911 final StringBuilder buffer = new StringBuilder("where TCP flags ");
912 boolean isFirst = true;
913 for (final TcpFlags item : flags) {
914 buffer.append(stringBitmaskOperand(item.getOp(), isFirst));
915 buffer.append(item.getValue());
921 return buffer.toString();
924 private static String stringBitmaskOperand(final BitmaskOperand op, final boolean isFirst) {
925 final StringBuilder buffer = new StringBuilder();
926 if (!op.isAndBit() && !isFirst) {
927 buffer.append("or ");
930 buffer.append("and ");
933 buffer.append("does ");
935 buffer.append("not ");
937 buffer.append("match ");
938 } else if (op.isNot()) {
939 buffer.append("is not ");
941 return buffer.toString();
944 private static String stringDscp(final List<Dscps> dscps) {
945 final StringBuilder buffer = new StringBuilder("where DSCP ");
946 boolean isFirst = true;
947 for (final Dscps item : dscps) {
948 buffer.append(stringNumericOperand(item.getOp(), isFirst));
949 buffer.append(item.getValue().getValue());
955 return buffer.toString();
958 private static String stringFragment(final List<Fragments> fragments) {
959 final StringBuilder buffer = new StringBuilder("where fragment ");
960 boolean isFirst = true;
961 for (final Fragments item : fragments) {
962 buffer.append(stringBitmaskOperand(item.getOp(), isFirst));
963 buffer.append(stringFragment(item.getValue()));
968 return buffer.toString();
971 private static String stringFragment(final Fragment fragment) {
972 final StringBuilder buffer = new StringBuilder();
973 if (fragment.isDoNot()) {
974 buffer.append("'DO NOT' ");
976 if (fragment.isFirst()) {
977 buffer.append("'IS FIRST' ");
979 if (fragment.isLast()) {
980 buffer.append("'IS LAST' ");
982 if (fragment.isIsA()) {
983 buffer.append("'IS A' ");
985 return buffer.toString();