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;
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;
103 public class FSNlriParser implements NlriParser, NlriSerializer {
104 private static final Logger LOG = LoggerFactory.getLogger(FSNlriParser.class);
106 private static final NodeIdentifier FLOWSPEC_TYPE_NID = new NodeIdentifier(FlowspecType.QNAME);
108 static final NodeIdentifier COMPONENT_TYPE_NID = new NodeIdentifier(QName.cachedReference(QName.create(Flowspec.QNAME, "component-type")));
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);
123 private static final int NLRI_LENGTH = 1;
124 private static final int NLRI_LENGTH_EXTENDED = 2;
126 * Add this constant to length value to achieve all ones in the leftmost nibble.
128 private static final int LENGTH_MAGIC = 61440;
130 private static final int OPERAND_LENGTH = 8;
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;
140 private static final int NOT = 6;
141 private static final int MATCH = 7;
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;
148 private static final int MAX_NLRI_LENGTH = 4095;
149 private static final int MAX_NLRI_LENGTH_ONE_BYTE = 240;
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);
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);
173 * Serializes Flowspec component type that has maximum of 2B sized value field and numeric operand.
175 * @param list of items to be serialized
176 * @param nlriByteBuf where the items will be serialized
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);
188 * Serializes Flowspec component type that has maximum of 1B sized value field and numeric operand.
190 * @param list of items to be serialized
191 * @param nlriByteBuf where the items will be serialized
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);
201 * Serializes Flowspec NLRI to ByteBuf.
203 * @param flows flowspec NLRI to be serialized
204 * @param buffer where flowspec NLRI will be serialized
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()));
216 nlriByteBuf.writeBytes(Ipv4Util.bytesForPrefixBegin(((SourcePrefixCase) value).getSourcePrefix()));
219 serializeNumericTwoByteValue(((ProtocolIpCase) value).getProtocolIps(), nlriByteBuf);
222 serializeNumericTwoByteValue(((PortCase) value).getPorts(), nlriByteBuf);
224 case DestinationPort:
225 serializeNumericTwoByteValue(((DestinationPortCase) value).getDestinationPorts(), nlriByteBuf);
228 serializeNumericTwoByteValue(((SourcePortCase) value).getSourcePorts(), nlriByteBuf);
231 serializeNumericOneByteValue(((IcmpTypeCase) value).getTypes(), nlriByteBuf);
234 serializeNumericOneByteValue(((IcmpCodeCase) value).getCodes(), nlriByteBuf);
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);
246 serializeNumericTwoByteValue(((PacketLengthCase) value).getPacketLengths(), nlriByteBuf);
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);
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()));
263 LOG.warn("Unknown Component Type.");
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());
271 buffer.writeShort(nlriByteBuf.readableBytes() + LENGTH_MAGIC);
273 buffer.writeBytes(nlriByteBuf);
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.
281 * @param value integer to be written
282 * @param buffer ByteBuf where the value will be written
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);
292 buffer.writeLong(value);
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);
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);
318 public void parseNlri(final ByteBuf nlri, final MpUnreachNlriBuilder builder) throws BGPParsingException {
319 if (!nlri.isReadable()) {
322 final List<Flowspec> dst = parseNlri(nlri);
324 builder.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(
325 new DestinationFlowspecCaseBuilder().setDestinationFlowspec(
326 new DestinationFlowspecBuilder().setFlowspec(
327 dst).build()).build()).build());
331 public void parseNlri(final ByteBuf nlri, final MpReachNlriBuilder builder) throws BGPParsingException {
332 if (!nlri.isReadable()) {
335 final List<Flowspec> dst = parseNlri(nlri);
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());
344 * Parses Flowspec NLRI into list of Flowspec.
346 * @param nlri byte representation of NLRI which will be parsed
347 * @return list of Flowspec
349 public static List<Flowspec> parseNlri(final ByteBuf nlri) throws BGPParsingException {
350 if (!nlri.isReadable()) {
353 final List<Flowspec> fss = new ArrayList<>();
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);
360 while (nlri.isReadable()) {
361 final FlowspecBuilder builder = new FlowspecBuilder();
363 final ComponentType type = ComponentType.forValue(nlri.readUnsignedByte());
364 builder.setComponentType(type);
366 case DestinationPrefix:
367 builder.setFlowspecType(new DestinationPrefixCaseBuilder().setDestinationPrefix(Ipv4Util.prefixForByteBuf(nlri)).build());
370 builder.setFlowspecType(new SourcePrefixCaseBuilder().setSourcePrefix(Ipv4Util.prefixForByteBuf(nlri)).build());
373 builder.setFlowspecType(new ProtocolIpCaseBuilder().setProtocolIps(parseProtocolIp(nlri)).build());
376 builder.setFlowspecType(new PortCaseBuilder().setPorts(parsePort(nlri)).build());
378 case DestinationPort:
379 builder.setFlowspecType(new DestinationPortCaseBuilder().setDestinationPorts(parseDestinationPort(nlri)).build());
382 builder.setFlowspecType(new SourcePortCaseBuilder().setSourcePorts(parseSourcePort(nlri)).build());
385 builder.setFlowspecType(new IcmpTypeCaseBuilder().setTypes(parseIcmpType(nlri)).build());
388 builder.setFlowspecType(new IcmpCodeCaseBuilder().setCodes(parseIcmpCode(nlri)).build());
391 builder.setFlowspecType(new TcpFlagsCaseBuilder().setTcpFlags(parseTcpFlags(nlri)).build());
394 builder.setFlowspecType(new PacketLengthCaseBuilder().setPacketLengths(parsePacketLength(nlri)).build());
397 builder.setFlowspecType(new DscpCaseBuilder().setDscps(parseDscp(nlri)).build());
400 builder.setFlowspecType(new FragmentCaseBuilder().setFragments(parseFragment(nlri)).build());
405 fss.add(builder.build());
410 private static List<ProtocolIps> parseProtocolIp(final ByteBuf nlri) {
411 final List<ProtocolIps> ips = new ArrayList<>();
413 // we can do this as all fields will be rewritten in the cycle
414 final ProtocolIpsBuilder builder = new ProtocolIpsBuilder();
416 final byte b = nlri.readByte();
417 final NumericOperand op = parseNumeric(b);
419 final short length = parseLength(b);
420 builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
421 end = op.isEndOfList();
422 ips.add(builder.build());
427 private static List<Ports> parsePort(final ByteBuf nlri) {
428 final List<Ports> ports = new ArrayList<>();
430 // we can do this as all fields will be rewritten in the cycle
431 final PortsBuilder builder = new PortsBuilder();
433 final byte b = nlri.readByte();
434 final NumericOperand op = parseNumeric(b);
436 final short length = parseLength(b);
437 builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
438 end = op.isEndOfList();
439 ports.add(builder.build());
444 private static List<DestinationPorts> parseDestinationPort(final ByteBuf nlri) {
445 final List<DestinationPorts> ports = new ArrayList<>();
447 // we can do this as all fields will be rewritten in the cycle
448 final DestinationPortsBuilder builder = new DestinationPortsBuilder();
450 final byte b = nlri.readByte();
451 final NumericOperand op = parseNumeric(b);
453 final short length = parseLength(b);
454 builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
455 end = op.isEndOfList();
456 ports.add(builder.build());
461 private static List<SourcePorts> parseSourcePort(final ByteBuf nlri) {
462 final List<SourcePorts> ports = new ArrayList<>();
464 // we can do this as all fields will be rewritten in the cycle
465 final SourcePortsBuilder builder = new SourcePortsBuilder();
467 final byte b = nlri.readByte();
468 final NumericOperand op = parseNumeric(b);
470 final short length = parseLength(b);
471 builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
472 end = op.isEndOfList();
473 ports.add(builder.build());
478 private static List<Types> parseIcmpType(final ByteBuf nlri) {
479 final List<Types> types = new ArrayList<>();
481 // we can do this as all fields will be rewritten in the cycle
482 final TypesBuilder builder = new TypesBuilder();
484 final byte b = nlri.readByte();
485 final NumericOperand op = parseNumeric(b);
487 builder.setValue(nlri.readUnsignedByte());
488 end = op.isEndOfList();
489 types.add(builder.build());
494 private static List<Codes> parseIcmpCode(final ByteBuf nlri) {
495 final List<Codes> codes = new ArrayList<>();
497 // we can do this as all fields will be rewritten in the cycle
498 final CodesBuilder builder = new CodesBuilder();
500 final byte b = nlri.readByte();
501 final NumericOperand op = parseNumeric(b);
503 builder.setValue(nlri.readUnsignedByte());
504 end = op.isEndOfList();
505 codes.add(builder.build());
510 private static List<TcpFlags> parseTcpFlags(final ByteBuf nlri) {
511 final List<TcpFlags> flags = new ArrayList<>();
513 // we can do this as all fields will be rewritten in the cycle
514 final TcpFlagsBuilder builder = new TcpFlagsBuilder();
516 final byte b = nlri.readByte();
517 final BitmaskOperand op = parseBitmask(b);
519 final short length = parseLength(b);
520 builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
521 end = op.isEndOfList();
522 flags.add(builder.build());
527 private static List<PacketLengths> parsePacketLength(final ByteBuf nlri) {
528 final List<PacketLengths> plengths = new ArrayList<>();
530 // we can do this as all fields will be rewritten in the cycle
531 final PacketLengthsBuilder builder = new PacketLengthsBuilder();
533 final byte b = nlri.readByte();
534 // RFC does not specify which operand to use
535 final NumericOperand op = parseNumeric(b);
537 final short length = parseLength(b);
538 builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
539 end = op.isEndOfList();
540 plengths.add(builder.build());
545 private static List<Dscps> parseDscp(final ByteBuf nlri) {
546 final List<Dscps> dscps = new ArrayList<>();
548 // we can do this as all fields will be rewritten in the cycle
549 final DscpsBuilder builder = new DscpsBuilder();
551 final byte b = nlri.readByte();
552 // RFC does not specify operator
553 final NumericOperand op = parseNumeric(b);
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());
562 private static List<Fragments> parseFragment(final ByteBuf nlri) {
563 final List<Fragments> fragments = new ArrayList<>();
565 // we can do this as all fields will be rewritten in the cycle
566 final FragmentsBuilder builder = new FragmentsBuilder();
568 final byte b = nlri.readByte();
569 final BitmaskOperand op = parseBitmask(b);
571 builder.setValue(parseFragment(nlri.readByte()));
572 end = op.isEndOfList();
573 fragments.add(builder.build());
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));
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));
589 public static short parseLength(final byte op) {
590 return (short) (1 << ((op & LENGTH_BITMASK) >> LENGTH_SHIFT));
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));
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());
607 public static String stringNlri(final DataContainerNode<?> flowspec) {
608 return stringNlri(extractFlowspec((MapEntryNode) flowspec));
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()));
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()))
624 } else if (fsType.getChild(PROTOCOL_IP_NID).isPresent()) {
626 fs.setFlowspecType(new ProtocolIpCaseBuilder().build());
627 } else if (fsType.getChild(PORTS_NID).isPresent()) {
629 fs.setFlowspecType(new PortCaseBuilder().build());
630 } else if (fsType.getChild(DEST_PORT_NID).isPresent()) {
632 fs.setFlowspecType(new DestinationPortCaseBuilder().build());
633 } else if (fsType.getChild(SOURCE_PORT_NID).isPresent()) {
635 fs.setFlowspecType(new SourcePortCaseBuilder().build());
636 } else if (fsType.getChild(ICMP_TYPE_NID).isPresent()) {
638 fs.setFlowspecType(new IcmpTypeCaseBuilder().build());
639 } else if (fsType.getChild(ICMP_CODE_NID).isPresent()) {
641 fs.setFlowspecType(new IcmpCodeCaseBuilder().build());
642 } else if (fsType.getChild(TCP_FLAGS_NID).isPresent()) {
644 fs.setFlowspecType(new TcpFlagsCaseBuilder().build());
645 } else if (fsType.getChild(PACKET_LENGTHS_NID).isPresent()) {
647 fs.setFlowspecType(new PacketLengthCaseBuilder().build());
648 } else if (fsType.getChild(DSCP_NID).isPresent()) {
650 fs.setFlowspecType(new DscpCaseBuilder().build());
651 } else if (fsType.getChild(FRAGMENT_NID).isPresent()) {
653 fs.setFlowspecType(new FragmentCaseBuilder().build());
659 private static ComponentType componentTypeValue(final String compType) {
661 case "destination-prefix":
662 return ComponentType.DestinationPrefix;
663 case "source-prefix":
664 return ComponentType.SourcePrefix;
666 return ComponentType.ProtocolIp;
668 return ComponentType.Port;
669 case "destination-port":
670 return ComponentType.DestinationPort;
672 return ComponentType.SourcePort;
674 return ComponentType.IcmpType;
676 return ComponentType.IcmpCode;
678 return ComponentType.TcpFlags;
679 case "packet-length":
680 return ComponentType.PacketLength;
682 return ComponentType.Dscp;
684 return ComponentType.Fragment;
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());
700 buffer.append("from ");
701 buffer.append(((SourcePrefixCase) value).getSourcePrefix().getValue());
704 buffer.append("where protocol ");
705 buffer.append(stringNumericTwo(((ProtocolIpCase) value).getProtocolIps()));
708 buffer.append("where port ");
709 buffer.append(stringNumericTwo(((PortCase) value).getPorts()));
711 case DestinationPort:
712 buffer.append("where destination port ");
713 buffer.append(stringNumericTwo(((DestinationPortCase) value).getDestinationPorts()));
716 buffer.append("where source port ");
717 buffer.append(stringNumericTwo(((SourcePortCase) value).getSourcePorts()));
720 buffer.append("where ICMP type ");
721 buffer.append(stringNumericOne(((IcmpTypeCase) value).getTypes()));
724 buffer.append("where ICMP code ");
725 buffer.append(stringNumericOne(((IcmpCodeCase) value).getCodes()));
728 buffer.append(stringTcpFlags(((TcpFlagsCase) value).getTcpFlags()));
731 buffer.append("where packet length ");
732 buffer.append(stringNumericTwo(((PacketLengthCase) value).getPacketLengths()));
735 buffer.append(stringDscp(((DscpCase) value).getDscps()));
738 buffer.append(stringFragment(((FragmentCase) value).getFragments()));
741 LOG.warn("Skipping unhandled component type {}" , flow.getComponentType());
744 return buffer.toString();
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());
758 return buffer.toString();
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());
772 return buffer.toString();
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 ");
781 buffer.append("and ");
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();
791 buffer.append("equals to ");
793 if (op.isLessThan()) {
794 buffer.append("is less than ");
796 if (op.isGreaterThan()) {
797 buffer.append("is greater than ");
799 return buffer.toString();
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());
813 return buffer.toString();
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 ");
822 buffer.append("and ");
825 buffer.append("does ");
827 buffer.append("not ");
829 buffer.append("match ");
830 } else if (op.isNot()) {
831 buffer.append("is not ");
833 return buffer.toString();
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());
847 return buffer.toString();
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()));
860 return buffer.toString();
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' ");
868 if (fragment.isFirst()) {
869 buffer.append("'IS FIRST' ");
871 if (fragment.isLast()) {
872 buffer.append("'IS LAST' ");
874 if (fragment.isIsA()) {
875 buffer.append("'IS A' ");
877 return buffer.toString();