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 static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.VisibleForTesting;
13 import com.google.common.base.Joiner;
14 import com.google.common.base.Preconditions;
15 import io.netty.buffer.ByteBuf;
16 import io.netty.buffer.Unpooled;
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.Optional;
21 import java.util.stream.Collectors;
22 import javax.annotation.Nonnull;
23 import javax.annotation.Nullable;
24 import org.opendaylight.protocol.bgp.flowspec.handlers.BitmaskOperandParser;
25 import org.opendaylight.protocol.bgp.flowspec.handlers.NumericOneByteOperandParser;
26 import org.opendaylight.protocol.bgp.flowspec.handlers.NumericTwoByteOperandParser;
27 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
28 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
29 import org.opendaylight.protocol.bgp.parser.spi.MultiPathSupportUtil;
30 import org.opendaylight.protocol.bgp.parser.spi.NlriParser;
31 import org.opendaylight.protocol.bgp.parser.spi.NlriSerializer;
32 import org.opendaylight.protocol.bgp.parser.spi.PathIdUtil;
33 import org.opendaylight.protocol.bgp.parser.spi.PeerSpecificParserConstraint;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.Dscp;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.Fragment;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.Flowspec;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.FlowspecBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.FlowspecType;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.DestinationPortCase;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.DestinationPortCaseBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.DscpCase;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.DscpCaseBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.FragmentCase;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.FragmentCaseBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.IcmpCodeCase;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.IcmpCodeCaseBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.IcmpTypeCase;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.IcmpTypeCaseBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.PacketLengthCase;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.PacketLengthCaseBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.PortCase;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.PortCaseBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.SourcePortCase;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.SourcePortCaseBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.TcpFlagsCase;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.TcpFlagsCaseBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.destination.port._case.DestinationPorts;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.destination.port._case.DestinationPortsBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.dscp._case.Dscps;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.dscp._case.DscpsBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.fragment._case.Fragments;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.fragment._case.FragmentsBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.icmp.code._case.Codes;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.icmp.code._case.CodesBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.icmp.type._case.Types;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.icmp.type._case.TypesBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.packet.length._case.PacketLengths;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.packet.length._case.PacketLengthsBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.port._case.Ports;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.port._case.PortsBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.source.port._case.SourcePorts;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.source.port._case.SourcePortsBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.tcp.flags._case.TcpFlags;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.flowspec.flowspec.type.tcp.flags._case.TcpFlagsBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.group.ipv4.flowspec.flowspec.type.DestinationPrefixCase;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev180329.flowspec.destination.group.ipv4.flowspec.flowspec.type.SourcePrefixCase;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.PathId;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.Attributes;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.Attributes1;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.Attributes2;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.destination.DestinationType;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpReachNlriBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpUnreachNlriBuilder;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.reach.nlri.AdvertizedRoutes;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.unreach.nlri.WithdrawnRoutes;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.AddressFamily;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.SubsequentAddressFamily;
90 import org.opendaylight.yangtools.yang.common.QName;
91 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
92 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
93 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
94 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
95 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
96 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
97 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
98 import org.slf4j.Logger;
99 import org.slf4j.LoggerFactory;
101 public abstract class AbstractFlowspecNlriParser implements NlriParser, NlriSerializer {
102 private static final Logger LOG = LoggerFactory.getLogger(AbstractFlowspecNlriParser.class);
105 static final NodeIdentifier FLOWSPEC_NID = new NodeIdentifier(Flowspec.QNAME);
107 static final NodeIdentifier FLOWSPEC_TYPE_NID = new NodeIdentifier(FlowspecType.QNAME);
108 public static final NodeIdentifier DEST_PREFIX_NID
109 = new NodeIdentifier(QName.create(DestinationPrefixCase.QNAME, "destination-prefix").intern());
110 public static final NodeIdentifier SOURCE_PREFIX_NID
111 = new NodeIdentifier(QName.create(SourcePrefixCase.QNAME, "source-prefix").intern());
113 static final NodeIdentifier PORTS_NID = new NodeIdentifier(Ports.QNAME);
115 static final NodeIdentifier DEST_PORT_NID = new NodeIdentifier(DestinationPorts.QNAME);
117 static final NodeIdentifier SOURCE_PORT_NID = new NodeIdentifier(SourcePorts.QNAME);
119 static final NodeIdentifier ICMP_TYPE_NID = new NodeIdentifier(Types.QNAME);
121 static final NodeIdentifier ICMP_CODE_NID = new NodeIdentifier(Codes.QNAME);
123 static final NodeIdentifier TCP_FLAGS_NID = new NodeIdentifier(TcpFlags.QNAME);
125 static final NodeIdentifier PACKET_LENGTHS_NID = new NodeIdentifier(PacketLengths.QNAME);
127 static final NodeIdentifier DSCP_NID = new NodeIdentifier(Dscps.QNAME);
129 static final NodeIdentifier FRAGMENT_NID = new NodeIdentifier(Fragments.QNAME);
131 public static final NodeIdentifier OP_NID
132 = new NodeIdentifier(QName.create(Flowspec.QNAME.getModule(), "op"));
134 public static final NodeIdentifier VALUE_NID
135 = new NodeIdentifier(QName.create(Flowspec.QNAME.getModule(), "value"));
137 protected final SimpleFlowspecTypeRegistry flowspecTypeRegistry;
140 * Add this constant to length value to achieve all ones in the leftmost nibble.
142 private static final int LENGTH_MAGIC = 61440;
143 private static final int MAX_NLRI_LENGTH = 0xFFF;
144 private static final int MAX_NLRI_LENGTH_ONE_BYTE = 0xF0;
147 static final String DO_NOT_VALUE = "do-not";
149 static final String FIRST_VALUE = "first";
151 static final String LAST_VALUE = "last";
153 static final String IS_A_VALUE = "is-a";
155 private static final String FLOW_SEPARATOR = " AND ";
157 protected AbstractFlowspecNlriParser(final SimpleFlowspecTypeRegistry flowspecTypeRegistry) {
158 this.flowspecTypeRegistry = requireNonNull(flowspecTypeRegistry);
161 protected abstract void serializeMpReachNlri(final DestinationType dstType, final ByteBuf byteAggregator);
163 protected abstract void serializeMpUnreachNlri(final DestinationType dstType, final ByteBuf byteAggregator);
165 public abstract void extractSpecificFlowspec(final ChoiceNode fsType, final FlowspecBuilder fsBuilder);
167 protected abstract void stringSpecificFSNlriType(final FlowspecType value, final StringBuilder buffer);
170 * Create withdrawn destination type
172 * @param nlriFields a list of NLRI fields to be included in the destination type
173 * @param pathId associated path id with given NLRI
174 * @return created destination type
176 public abstract DestinationType createWithdrawnDestinationType(@Nonnull Object[] nlriFields,
177 @Nullable PathId pathId);
180 * Create advertized destination type
182 * @param nlriFields a list of NLRI fields to be included in the destination type
183 * @param pathId associated path id with given NLRI
184 * @return created destination type
186 public abstract DestinationType createAdvertizedRoutesDestinationType(@Nonnull Object[] nlriFields, @Nullable PathId pathId);
189 public final void serializeAttribute(final Attributes pathAttributes, final ByteBuf byteAggregator) {
190 final Attributes1 pathAttributes1 = pathAttributes.augmentation(Attributes1.class);
191 final Attributes2 pathAttributes2 = pathAttributes.augmentation(Attributes2.class);
193 if (pathAttributes1 != null) {
194 final AdvertizedRoutes routes = pathAttributes1.getMpReachNlri().getAdvertizedRoutes();
195 if (routes != null) {
196 serializeMpReachNlri(routes.getDestinationType(), byteAggregator);
200 if (pathAttributes2 != null) {
201 final WithdrawnRoutes routes = pathAttributes2.getMpUnreachNlri().getWithdrawnRoutes();
202 if (routes != null) {
203 serializeMpUnreachNlri(routes.getDestinationType(), byteAggregator);
208 protected void serializeNlri(@Nonnull final Object[] nlriFields, @Nonnull final ByteBuf buffer) {
209 final List<Flowspec> flowspecList = (List<Flowspec>) nlriFields[0];
210 serializeNlri(flowspecList, buffer);
213 protected final void serializeNlri(final List<Flowspec> flowspecList, @Nonnull final ByteBuf buffer) {
214 if (flowspecList != null) {
215 for (final Flowspec flow : flowspecList) {
216 this.flowspecTypeRegistry.serializeFlowspecType(flow.getFlowspecType(), buffer);
222 * Serializes Flowspec NLRI to ByteBuf.
224 * @param nlriFields NLRI fields to be serialized
226 * @param buffer where flowspec NLRI will be serialized
228 protected final void serializeNlri(@Nonnull final Object[] nlriFields, @Nullable final PathId pathId,
229 @Nonnull final ByteBuf buffer) {
230 final ByteBuf nlriByteBuf = Unpooled.buffer();
231 PathIdUtil.writePathId(pathId, buffer);
233 serializeNlri(nlriFields, nlriByteBuf);
235 Preconditions.checkState(nlriByteBuf.readableBytes() <= MAX_NLRI_LENGTH,
236 "Maximum length of Flowspec NLRI reached.");
237 if (nlriByteBuf.readableBytes() <= MAX_NLRI_LENGTH_ONE_BYTE) {
238 buffer.writeByte(nlriByteBuf.readableBytes());
240 buffer.writeShort(nlriByteBuf.readableBytes() + LENGTH_MAGIC);
242 buffer.writeBytes(nlriByteBuf);
245 public String stringNlri(final DataContainerNode<?> flowspec) {
246 return stringNlri(extractFlowspec(flowspec));
249 public final List<Flowspec> extractFlowspec(final DataContainerNode<?> route) {
250 requireNonNull(route, "Cannot extract flowspec from null route.");
251 final List<Flowspec> fsList = new ArrayList<>();
252 final Optional<DataContainerChild<? extends PathArgument, ?>> flowspecs = route.getChild(FLOWSPEC_NID);
253 if (flowspecs.isPresent()) {
254 for (final UnkeyedListEntryNode flowspec : ((UnkeyedListNode) flowspecs.get()).getValue()) {
255 final FlowspecBuilder fsBuilder = new FlowspecBuilder();
256 final Optional<DataContainerChild<?, ?>> flowspecType = flowspec.getChild(FLOWSPEC_TYPE_NID);
257 if (flowspecType.isPresent()) {
258 final ChoiceNode fsType = (ChoiceNode) flowspecType.get();
259 processFlowspecType(fsType, fsBuilder);
261 fsList.add(fsBuilder.build());
267 private void processFlowspecType(final ChoiceNode fsType, final FlowspecBuilder fsBuilder) {
268 if (fsType.getChild(PORTS_NID).isPresent()) {
269 fsBuilder.setFlowspecType(new PortCaseBuilder()
270 .setPorts(createPorts((UnkeyedListNode) fsType.getChild(PORTS_NID).get())).build());
271 } else if (fsType.getChild(DEST_PORT_NID).isPresent()) {
272 fsBuilder.setFlowspecType(new DestinationPortCaseBuilder()
273 .setDestinationPorts(createDestinationPorts((UnkeyedListNode) fsType.getChild(DEST_PORT_NID).get()))
275 } else if (fsType.getChild(SOURCE_PORT_NID).isPresent()) {
276 fsBuilder.setFlowspecType(new SourcePortCaseBuilder()
277 .setSourcePorts(createSourcePorts((UnkeyedListNode) fsType.getChild(SOURCE_PORT_NID).get()))
279 } else if (fsType.getChild(ICMP_TYPE_NID).isPresent()) {
280 fsBuilder.setFlowspecType(new IcmpTypeCaseBuilder()
281 .setTypes(createTypes((UnkeyedListNode) fsType.getChild(ICMP_TYPE_NID).get())).build());
282 } else if (fsType.getChild(ICMP_CODE_NID).isPresent()) {
283 fsBuilder.setFlowspecType(new IcmpCodeCaseBuilder()
284 .setCodes(createCodes((UnkeyedListNode) fsType.getChild(ICMP_CODE_NID).get())).build());
285 } else if (fsType.getChild(TCP_FLAGS_NID).isPresent()) {
286 fsBuilder.setFlowspecType(new TcpFlagsCaseBuilder()
287 .setTcpFlags(createTcpFlags((UnkeyedListNode) fsType.getChild(TCP_FLAGS_NID).get())).build());
288 } else if (fsType.getChild(PACKET_LENGTHS_NID).isPresent()) {
289 fsBuilder.setFlowspecType(new PacketLengthCaseBuilder()
290 .setPacketLengths(createPacketLengths((UnkeyedListNode) fsType.getChild(PACKET_LENGTHS_NID).get()))
292 } else if (fsType.getChild(DSCP_NID).isPresent()) {
293 fsBuilder.setFlowspecType(new DscpCaseBuilder()
294 .setDscps(createDscpsLengths((UnkeyedListNode) fsType.getChild(DSCP_NID).get())).build());
295 } else if (fsType.getChild(FRAGMENT_NID).isPresent()) {
296 fsBuilder.setFlowspecType(new FragmentCaseBuilder()
297 .setFragments(createFragments((UnkeyedListNode) fsType.getChild(FRAGMENT_NID).get())).build());
299 extractSpecificFlowspec(fsType, fsBuilder);
303 private static List<Ports> createPorts(final UnkeyedListNode portsData) {
304 final List<Ports> ports = new ArrayList<>();
306 for (final UnkeyedListEntryNode node : portsData.getValue()) {
307 final PortsBuilder portsBuilder = new PortsBuilder();
308 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
309 opValue.ifPresent(dataContainerChild -> portsBuilder
310 .setOp(NumericTwoByteOperandParser.INSTANCE.create((Set<String>) dataContainerChild.getValue())));
311 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
312 valueNode.ifPresent(dataContainerChild -> portsBuilder.setValue((Integer) dataContainerChild.getValue()));
313 ports.add(portsBuilder.build());
319 private static List<DestinationPorts> createDestinationPorts(final UnkeyedListNode destinationPortsData) {
320 final List<DestinationPorts> destinationPorts = new ArrayList<>();
322 for (final UnkeyedListEntryNode node : destinationPortsData.getValue()) {
323 final DestinationPortsBuilder destPortsBuilder = new DestinationPortsBuilder();
324 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
325 opValue.ifPresent(dataContainerChild -> destPortsBuilder.setOp(NumericTwoByteOperandParser
326 .INSTANCE.create((Set<String>) dataContainerChild.getValue())));
327 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
328 valueNode.ifPresent(dataContainerChild
329 -> destPortsBuilder.setValue((Integer) dataContainerChild.getValue()));
330 destinationPorts.add(destPortsBuilder.build());
333 return destinationPorts;
336 private static List<SourcePorts> createSourcePorts(final UnkeyedListNode sourcePortsData) {
337 final List<SourcePorts> sourcePorts = new ArrayList<>();
339 for (final UnkeyedListEntryNode node : sourcePortsData.getValue()) {
340 final SourcePortsBuilder sourcePortsBuilder = new SourcePortsBuilder();
341 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
342 opValue.ifPresent(dataContainerChild -> sourcePortsBuilder.setOp(NumericTwoByteOperandParser
343 .INSTANCE.create((Set<String>) dataContainerChild.getValue())));
344 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
345 valueNode.ifPresent(dataContainerChild
346 -> sourcePortsBuilder.setValue((Integer) dataContainerChild.getValue()));
347 sourcePorts.add(sourcePortsBuilder.build());
353 private static List<Types> createTypes(final UnkeyedListNode typesData) {
354 final List<Types> types = new ArrayList<>();
356 for (final UnkeyedListEntryNode node : typesData.getValue()) {
357 final TypesBuilder typesBuilder = new TypesBuilder();
358 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
359 opValue.ifPresent(dataContainerChild -> typesBuilder.setOp(NumericOneByteOperandParser
360 .INSTANCE.create((Set<String>) dataContainerChild.getValue())));
361 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
362 valueNode.ifPresent(dataContainerChild -> typesBuilder.setValue((Short) dataContainerChild.getValue()));
363 types.add(typesBuilder.build());
369 private static List<Codes> createCodes(final UnkeyedListNode codesData) {
370 final List<Codes> codes = new ArrayList<>();
372 for (final UnkeyedListEntryNode node : codesData.getValue()) {
373 final CodesBuilder codesBuilder = new CodesBuilder();
374 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
375 opValue.ifPresent(dataContainerChild -> codesBuilder.setOp(NumericOneByteOperandParser
376 .INSTANCE.create((Set<String>) dataContainerChild.getValue())));
377 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
378 valueNode.ifPresent(dataContainerChild -> codesBuilder.setValue((Short) dataContainerChild.getValue()));
379 codes.add(codesBuilder.build());
385 private static List<TcpFlags> createTcpFlags(final UnkeyedListNode tcpFlagsData) {
386 final List<TcpFlags> tcpFlags = new ArrayList<>();
388 for (final UnkeyedListEntryNode node : tcpFlagsData.getValue()) {
389 final TcpFlagsBuilder tcpFlagsBuilder = new TcpFlagsBuilder();
390 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
391 opValue.ifPresent(dataContainerChild -> tcpFlagsBuilder
392 .setOp(BitmaskOperandParser.INSTANCE.create((Set<String>) dataContainerChild.getValue())));
393 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
394 valueNode.ifPresent(dataContainerChild
395 -> tcpFlagsBuilder.setValue((Integer) dataContainerChild.getValue()));
396 tcpFlags.add(tcpFlagsBuilder.build());
402 private static List<PacketLengths> createPacketLengths(final UnkeyedListNode packetLengthsData) {
403 final List<PacketLengths> packetLengths = new ArrayList<>();
405 for (final UnkeyedListEntryNode node : packetLengthsData.getValue()) {
406 final PacketLengthsBuilder packetLengthsBuilder = new PacketLengthsBuilder();
407 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
408 opValue.ifPresent(dataContainerChild -> packetLengthsBuilder.setOp(NumericTwoByteOperandParser
409 .INSTANCE.create((Set<String>) dataContainerChild.getValue())));
410 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
411 valueNode.ifPresent(dataContainerChild
412 -> packetLengthsBuilder.setValue((Integer) dataContainerChild.getValue()));
413 packetLengths.add(packetLengthsBuilder.build());
416 return packetLengths;
419 private static List<Dscps> createDscpsLengths(final UnkeyedListNode dscpLengthsData) {
420 final List<Dscps> dscpsLengths = new ArrayList<>();
422 for (final UnkeyedListEntryNode node : dscpLengthsData.getValue()) {
423 final DscpsBuilder dscpsLengthsBuilder = new DscpsBuilder();
424 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
425 opValue.ifPresent(dataContainerChild -> dscpsLengthsBuilder.setOp(NumericOneByteOperandParser
426 .INSTANCE.create((Set<String>) dataContainerChild.getValue())));
427 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
428 valueNode.ifPresent(dataContainerChild
429 -> dscpsLengthsBuilder.setValue(new Dscp((Short) dataContainerChild.getValue())));
430 dscpsLengths.add(dscpsLengthsBuilder.build());
436 private static List<Fragments> createFragments(final UnkeyedListNode fragmentsData) {
437 final List<Fragments> fragments = new ArrayList<>();
439 for (final UnkeyedListEntryNode node : fragmentsData.getValue()) {
440 final FragmentsBuilder fragmentsBuilder = new FragmentsBuilder();
441 final Optional<DataContainerChild<? extends PathArgument, ?>> opValue = node.getChild(OP_NID);
442 opValue.ifPresent(dataContainerChild -> fragmentsBuilder.setOp(BitmaskOperandParser
443 .INSTANCE.create((Set<String>) dataContainerChild.getValue())));
444 final Optional<DataContainerChild<? extends PathArgument, ?>> valueNode = node.getChild(VALUE_NID);
445 valueNode.ifPresent(dataContainerChild
446 -> fragmentsBuilder.setValue(createFragment((Set<String>) dataContainerChild.getValue())));
447 fragments.add(fragmentsBuilder.build());
453 private static Fragment createFragment(final Set<String> data) {
454 return new Fragment(data.contains(DO_NOT_VALUE), data.contains(FIRST_VALUE), data.contains(IS_A_VALUE),
455 data.contains(LAST_VALUE));
458 protected final String stringNlri(final List<Flowspec> flows) {
459 final StringBuilder buffer = new StringBuilder("all packets ");
460 final Joiner joiner = Joiner.on(FLOW_SEPARATOR);
461 joiner.appendTo(buffer, flows.stream().map(this::encodeFlow).collect(Collectors.toList()));
462 return buffer.toString().replace(" ", " ");
466 final String encodeFlow(final Flowspec flow) {
467 final StringBuilder buffer = new StringBuilder();
468 final FlowspecType value = flow.getFlowspecType();
469 if (value instanceof PortCase) {
470 buffer.append("where port ");
471 buffer.append(NumericTwoByteOperandParser.INSTANCE.toString(((PortCase) value).getPorts()));
472 } else if (value instanceof DestinationPortCase) {
473 buffer.append("where destination port ");
474 buffer.append(NumericTwoByteOperandParser
475 .INSTANCE.toString(((DestinationPortCase) value).getDestinationPorts()));
476 } else if (value instanceof SourcePortCase) {
477 buffer.append("where source port ");
478 buffer.append(NumericTwoByteOperandParser.INSTANCE.toString(((SourcePortCase) value).getSourcePorts()));
479 } else if (value instanceof IcmpTypeCase) {
480 buffer.append("where ICMP type ");
481 buffer.append(NumericOneByteOperandParser.INSTANCE.toString(((IcmpTypeCase) value).getTypes()));
482 } else if (value instanceof IcmpCodeCase) {
483 buffer.append("where ICMP code ");
484 buffer.append(NumericOneByteOperandParser.INSTANCE.toString(((IcmpCodeCase) value).getCodes()));
485 } else if (value instanceof TcpFlagsCase) {
486 buffer.append(stringTcpFlags(((TcpFlagsCase) value).getTcpFlags()));
487 } else if (value instanceof PacketLengthCase) {
488 buffer.append("where packet length ");
489 buffer.append(NumericTwoByteOperandParser.INSTANCE.toString(((PacketLengthCase) value).getPacketLengths()));
490 } else if (value instanceof DscpCase) {
491 buffer.append(stringDscp(((DscpCase) value).getDscps()));
492 } else if (value instanceof FragmentCase) {
493 buffer.append(stringFragment(((FragmentCase) value).getFragments()));
495 stringSpecificFSNlriType(value, buffer);
497 return buffer.toString();
500 private static String stringTcpFlags(final List<TcpFlags> flags) {
501 final StringBuilder buffer = new StringBuilder("where TCP flags ");
502 boolean isFirst = true;
503 for (final TcpFlags item : flags) {
504 buffer.append(BitmaskOperandParser.INSTANCE.toString(item.getOp(), isFirst));
505 buffer.append(item.getValue());
511 return buffer.toString();
514 private static String stringDscp(final List<Dscps> dscps) {
515 final StringBuilder buffer = new StringBuilder("where DSCP ");
516 boolean isFirst = true;
517 for (final Dscps item : dscps) {
518 buffer.append(NumericOneByteOperandParser.INSTANCE.toString(item.getOp(), isFirst));
519 buffer.append(item.getValue().getValue());
525 return buffer.toString();
528 private static String stringFragment(final List<Fragments> fragments) {
529 final StringBuilder buffer = new StringBuilder("where fragment ");
530 boolean isFirst = true;
531 for (final Fragments item : fragments) {
532 buffer.append(BitmaskOperandParser.INSTANCE.toString(item.getOp(), isFirst));
533 buffer.append(stringFragment(item.getValue()));
538 return buffer.toString();
541 private static String stringFragment(final Fragment fragment) {
542 final StringBuilder buffer = new StringBuilder();
543 if (fragment.isDoNot()) {
544 buffer.append("'DO NOT' ");
546 if (fragment.isFirst()) {
547 buffer.append("'IS FIRST' ");
549 if (fragment.isLast()) {
550 buffer.append("'IS LAST' ");
552 if (fragment.isIsA()) {
553 buffer.append("'IS A' ");
555 return buffer.toString();
558 public static int readNlriLength(@Nonnull final ByteBuf nlri) {
559 requireNonNull(nlri, "NLRI information cannot be null");
560 Preconditions.checkState(nlri.isReadable(), "NLRI Byte buffer is not readable.");
561 int length = nlri.readUnsignedByte();
562 if (length >= MAX_NLRI_LENGTH_ONE_BYTE) {
563 length = (length << Byte.SIZE | nlri.readUnsignedByte()) & MAX_NLRI_LENGTH;
565 Preconditions.checkState(length > 0 && length <= nlri.readableBytes(),
566 "Invalid flowspec NLRI length %s", length);
571 * Parses Flowspec NLRI into list of Flowspec.
573 * @param nlri byte representation of NLRI which will be parsed
574 * @return list of Flowspec
576 protected final List<Flowspec> parseNlriFlowspecList(@Nonnull final ByteBuf nlri) throws BGPParsingException {
577 if (!nlri.isReadable()) {
580 final List<Flowspec> fss = new ArrayList<>();
582 while (nlri.isReadable()) {
583 int nlriLength = readNlriLength(nlri);
584 Preconditions.checkState(nlriLength > 0 && nlriLength <= nlri.readableBytes(),
585 "Invalid flowspec NLRI length %s", nlriLength);
586 LOG.trace("Flowspec NLRI length is {}", nlriLength);
588 while (nlriLength > 0) {
589 final int readableLength = nlri.readableBytes();
590 final FlowspecBuilder builder = new FlowspecBuilder();
591 builder.setFlowspecType(this.flowspecTypeRegistry.parseFlowspecType(nlri));
592 fss.add(builder.build());
593 final int flowspecTypeLength = readableLength - nlri.readableBytes();
594 nlriLength -= flowspecTypeLength;
596 Preconditions.checkState(nlriLength == 0,
597 "Remain NLRI length should be 0 instead of %s", nlriLength);
604 * Override this function to parse additional NLRI fields
606 * @param nlri NLRI buffer
607 * @return Parsed additional fields
610 protected Object[] parseNlri(@Nonnull final ByteBuf nlri) throws BGPParsingException {
611 return new Object[] {parseNlriFlowspecList(nlri)};
615 public final void parseNlri(@Nonnull final ByteBuf nlri, @Nonnull final MpReachNlriBuilder builder,
616 @Nullable final PeerSpecificParserConstraint constraint)
617 throws BGPParsingException {
618 if (!nlri.isReadable()) {
621 final PathId pathId = readPathId(nlri, builder.getAfi(), builder.getSafi(), constraint);
622 final Object[] nlriFields = parseNlri(nlri);
623 builder.setAdvertizedRoutes(
624 new AdvertizedRoutesBuilder()
626 createAdvertizedRoutesDestinationType(nlriFields, pathId)
632 protected static PathId readPathId(@Nonnull final ByteBuf nlri, final Class<? extends AddressFamily> afi,
633 final Class<? extends SubsequentAddressFamily> safi, final PeerSpecificParserConstraint constraint) {
634 if (MultiPathSupportUtil.isTableTypeSupported(constraint, new BgpTableTypeImpl(afi, safi))) {
635 return PathIdUtil.readPathId(nlri);
641 public final void parseNlri(@Nonnull final ByteBuf nlri, @Nonnull final MpUnreachNlriBuilder builder,
642 @Nullable final PeerSpecificParserConstraint constraint)
643 throws BGPParsingException {
644 if (!nlri.isReadable()) {
647 final PathId pathId = readPathId(nlri, builder.getAfi(), builder.getSafi(), constraint);
648 final Object[] nlriFields = parseNlri(nlri);
649 builder.setWithdrawnRoutes(
650 new WithdrawnRoutesBuilder()
652 createWithdrawnDestinationType(nlriFields, pathId)