BUG-2571 : added parser/serializer for flowspec NLRI 39/14639/7
authorDana Kutenicsova <dkutenic@cisco.com>
Fri, 30 Jan 2015 17:08:16 +0000 (18:08 +0100)
committerDana Kutenicsova <dkutenic@cisco.com>
Thu, 12 Feb 2015 09:54:26 +0000 (09:54 +0000)
Change-Id: I42a59f81a3d9023768f6ae526b5e15463d4b40f1
Signed-off-by: Dana Kutenicsova <dkutenic@cisco.com>
bgp/flowspec/src/main/java/org/opendaylight/protocol/bgp/flowspec/FSActivator.java
bgp/flowspec/src/main/java/org/opendaylight/protocol/bgp/flowspec/FSNlriParser.java [new file with mode: 0644]
bgp/flowspec/src/main/yang/bgp-flowspec.yang
bgp/flowspec/src/test/java/org/opendaylight/protocol/bgp/flowspec/FSNlriParserTest.java [new file with mode: 0644]
util/src/main/java/org/opendaylight/protocol/util/Values.java

index 2ee34be691018bcbe70104f01cb64e6b4f71f25d..b54242b229449a093f74dc284cdc7657747053a7 100644 (file)
@@ -14,6 +14,8 @@ import org.opendaylight.protocol.bgp.parser.spi.AbstractBGPExtensionProviderActi
 import org.opendaylight.protocol.bgp.parser.spi.BGPExtensionProviderContext;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.FlowspecSubsequentAddressFamily;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.ExtendedCommunities;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv4AddressFamily;
 
 public final class FSActivator extends AbstractBGPExtensionProviderActivator {
 
@@ -25,6 +27,10 @@ public final class FSActivator extends AbstractBGPExtensionProviderActivator {
 
         regs.add(context.registerSubsequentAddressFamily(FlowspecSubsequentAddressFamily.class, FLOWSPEC_SAFI));
 
+        regs.add(context.registerNlriParser(Ipv4AddressFamily.class, FlowspecSubsequentAddressFamily.class,
+                new FSNlriParser()));
+        regs.add(context.registerNlriSerializer(PathAttributes.class, new FSNlriParser()));
+
         final ExtendedCommunitiesAttributeParser extendedCommunitiesAttributeParser = new FSExtendedCommunitiesAttributeParser(context.getReferenceCache());
         regs.add(context.registerAttributeSerializer(ExtendedCommunities.class, extendedCommunitiesAttributeParser));
         regs.add(context.registerAttributeParser(ExtendedCommunitiesAttributeParser.TYPE, extendedCommunitiesAttributeParser));
diff --git a/bgp/flowspec/src/main/java/org/opendaylight/protocol/bgp/flowspec/FSNlriParser.java b/bgp/flowspec/src/main/java/org/opendaylight/protocol/bgp/flowspec/FSNlriParser.java
new file mode 100644 (file)
index 0000000..a037d29
--- /dev/null
@@ -0,0 +1,599 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.protocol.bgp.flowspec;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.UnsignedBytes;
+import com.google.common.primitives.UnsignedInts;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+import org.opendaylight.protocol.bgp.parser.BGPParsingException;
+import org.opendaylight.protocol.bgp.parser.spi.NlriParser;
+import org.opendaylight.protocol.bgp.parser.spi.NlriSerializer;
+import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.ByteBufWriteUtil;
+import org.opendaylight.protocol.util.Ipv4Util;
+import org.opendaylight.protocol.util.Values;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.BitmaskOperand;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.ComponentType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.NumericOneByteValue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.NumericOperand;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.NumericTwoByteValue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.Flowspec;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.FlowspecBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.FlowspecType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DestinationPortCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DestinationPortCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DestinationPrefixCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DestinationPrefixCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DscpCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DscpCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.FragmentCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.FragmentCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.IcmpCodeCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.IcmpCodeCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.IcmpTypeCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.IcmpTypeCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.PacketLengthCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.PacketLengthCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.PortCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.PortCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.ProtocolIpCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.ProtocolIpCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.SourcePortCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.SourcePortCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.SourcePrefixCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.SourcePrefixCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.TcpFlagsCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.TcpFlagsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.destination.port._case.DestinationPorts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.destination.port._case.DestinationPortsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.dscp._case.Dscps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.dscp._case.DscpsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.fragment._case.Fragments;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.fragment._case.FragmentsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.icmp.code._case.Codes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.icmp.code._case.CodesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.icmp.type._case.Types;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.icmp.type._case.TypesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.packet.length._case.PacketLengths;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.packet.length._case.PacketLengthsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.port._case.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.port._case.PortsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.protocol.ip._case.ProtocolIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.protocol.ip._case.ProtocolIpsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.source.port._case.SourcePorts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.source.port._case.SourcePortsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.tcp.flags._case.TcpFlags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.tcp.flags._case.TcpFlagsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.destination.flowspec._case.DestinationFlowspecBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlriBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlriBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.reach.nlri.AdvertizedRoutes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FSNlriParser implements NlriParser, NlriSerializer {
+    private static final Logger LOG = LoggerFactory.getLogger(FSNlriParser.class);
+
+    private static final int NLRI_LENGTH = 1;
+    private static final int NLRI_LENGTH_EXTENDED = 2;
+    /**
+     * Add this constant to length value to achieve all ones in the leftmost nibble.
+     */
+    private static final int LENGTH_MAGIC = 61440;
+
+    private static final int END_OF_LIST = 7;
+    private static final int AND_BIT = 6;
+    private static final int LENGTH_BITMASK = 48;
+    private static final int LENGTH_SHIFT = 4;
+    private static final int LESS_THAN = 2;
+    private static final int GREATER_THAN = 1;
+    private static final int EQUAL = 0;
+
+    private static final int NOT = 1;
+    private static final int MATCH = 0;
+
+    private static final int LAST_FRAGMENT = 7;
+    private static final int FIRST_FRAGMENT = 6;
+    private static final int IS_A_FRAGMENT = 5;
+    private static final int DONT_FRAGMENT = 4;
+
+    private static final int MAX_NLRI_LENGTH = 4095;
+    private static final int MAX_NLRI_LENGTH_ONE_BYTE = 240;
+
+    @Override
+    public void serializeAttribute(final DataObject attribute, final ByteBuf byteAggregator) {
+        Preconditions.checkArgument(attribute instanceof PathAttributes, "Attribute parameter is not a PathAttribute object.");
+        final PathAttributes pathAttributes = (PathAttributes) attribute;
+        final PathAttributes1 pathAttributes1 = pathAttributes.getAugmentation(PathAttributes1.class);
+        final PathAttributes2 pathAttributes2 = pathAttributes.getAugmentation(PathAttributes2.class);
+        if (pathAttributes1 != null) {
+            final AdvertizedRoutes routes = (pathAttributes1.getMpReachNlri()).getAdvertizedRoutes();
+            if (routes != null &&
+                routes.getDestinationType()
+                instanceof
+                org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecCase) {
+                final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecCase
+                linkstateCase = (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecCase) routes.getDestinationType();
+                serializeNlri(linkstateCase.getDestinationFlowspec().getFlowspec(), byteAggregator);
+            }
+        } else if (pathAttributes2 != null) {
+            final MpUnreachNlri mpUnreachNlri = pathAttributes2.getMpUnreachNlri();
+            if (mpUnreachNlri.getWithdrawnRoutes() != null && mpUnreachNlri.getWithdrawnRoutes().getDestinationType() instanceof DestinationFlowspecCase) {
+                final DestinationFlowspecCase flowspecCase = (DestinationFlowspecCase) mpUnreachNlri.getWithdrawnRoutes().getDestinationType();
+                serializeNlri(flowspecCase.getDestinationFlowspec().getFlowspec(), byteAggregator);
+            }
+        }
+    }
+
+    /**
+     * Serializes Flowspec component type that has maximum of 2B sized value field and numeric operand.
+     *
+     * @param list of items to be serialized
+     * @param nlriByteBuf where the items will be serialized
+     */
+    private static <T extends NumericTwoByteValue> void serializeNumericTwoByteValue(final List<T> list, final ByteBuf nlriByteBuf) {
+        for (final T item : list) {
+            final ByteBuf protoBuf = Unpooled.buffer();
+            writeShortest(item.getValue(), protoBuf);
+            serializeNumericOperand(item.getOp(), protoBuf.readableBytes(), nlriByteBuf);
+            nlriByteBuf.writeBytes(protoBuf);
+        }
+    }
+
+    /**
+     * Serializes Flowspec component type that has maximum of 1B sized value field and numeric operand.
+     *
+     * @param list of items to be serialized
+     * @param nlriByteBuf where the items will be serialized
+     */
+    private static <T extends NumericOneByteValue> void serializeNumericOneByteValue(final List<T> list, final ByteBuf nlriByteBuf) {
+        for (final T type : list) {
+            serializeNumericOperand(type.getOp(), 1, nlriByteBuf);
+            writeShortest(type.getValue(), nlriByteBuf);
+        }
+    }
+
+    /**
+     * Serializes Flowspec NLRI to ByteBuf.
+     *
+     * @param flow flowspec NLRI to be serialized
+     */
+    public static void serializeNlri(final List<Flowspec> flows, final ByteBuf buffer) {
+        final ByteBuf nlriByteBuf = Unpooled.buffer();
+        for (final Flowspec flow : flows) {
+            nlriByteBuf.writeByte(flow.getComponentType().getIntValue());
+            final FlowspecType value = flow.getFlowspecType();
+            switch (flow.getComponentType()) {
+            case DestinationPrefix:
+                nlriByteBuf.writeBytes(Ipv4Util.bytesForPrefixBegin(((DestinationPrefixCase)value).getDestinationPrefix()));
+                break;
+            case SourcePrefix:
+                nlriByteBuf.writeBytes(Ipv4Util.bytesForPrefixBegin(((SourcePrefixCase)value).getSourcePrefix()));
+                break;
+            case ProtocolIp:
+                serializeNumericTwoByteValue(((ProtocolIpCase)value).getProtocolIps(), nlriByteBuf);
+                break;
+            case Port:
+                serializeNumericTwoByteValue(((PortCase)value).getPorts(), nlriByteBuf);
+                break;
+            case DestinationPort:
+                serializeNumericTwoByteValue(((DestinationPortCase)value).getDestinationPorts(), nlriByteBuf);
+                break;
+            case SourcePort:
+                serializeNumericTwoByteValue(((SourcePortCase)value).getSourcePorts(), nlriByteBuf);
+                break;
+            case IcmpType:
+                serializeNumericOneByteValue(((IcmpTypeCase)value).getTypes(), nlriByteBuf);
+                break;
+            case IcmpCode:
+                serializeNumericOneByteValue(((IcmpCodeCase)value).getCodes(), nlriByteBuf);
+                break;
+            case TcpFlags:
+                final List<TcpFlags> flags = ((TcpFlagsCase)value).getTcpFlags();
+                for (final TcpFlags flag : flags) {
+                    final ByteBuf flagsBuf = Unpooled.buffer();
+                    writeShortest(flag.getValue(), flagsBuf);
+                    serializeBitmaskOperand(flag.getOp(), flagsBuf.readableBytes(), nlriByteBuf);
+                    nlriByteBuf.writeBytes(flagsBuf);
+                }
+                break;
+            case PacketLength:
+                serializeNumericTwoByteValue(((PacketLengthCase)value).getPacketLengths(), nlriByteBuf);
+                break;
+            case Dscp:
+                final List<Dscps> dscps = ((DscpCase)value).getDscps();
+                for (final Dscps dscp : dscps) {
+                    serializeNumericOperand(dscp.getOp(), 1, nlriByteBuf);
+                    writeShortest(dscp.getValue().getValue(), nlriByteBuf);
+                }
+                break;
+            case Fragment:
+                final List<Fragments> fragments = ((FragmentCase)value).getFragments();
+                for (final Fragments fragment : fragments) {
+                    serializeBitmaskOperand(fragment.getOp(), 1, nlriByteBuf);
+                    nlriByteBuf.writeByte(serializeFragment(fragment.getValue()));
+                }
+                break;
+            default:
+                LOG.warn("Unknown Component Type.");
+                break;
+            }
+        }
+        Preconditions.checkState(nlriByteBuf.readableBytes() <= MAX_NLRI_LENGTH, "Maximum length of Flowspec NLRI reached.");
+        if (nlriByteBuf.readableBytes() <= MAX_NLRI_LENGTH_ONE_BYTE) {
+            buffer.writeByte(nlriByteBuf.readableBytes());
+        } else {
+            buffer.writeShort(nlriByteBuf.readableBytes() + LENGTH_MAGIC);
+        }
+        buffer.writeBytes(nlriByteBuf);
+    }
+
+    /**
+     * Given the integer values, this method instead of writing the value
+     * in 4B field, compresses the value to lowest required byte field
+     * depending on the value.
+     *
+     * @param value integer to be written
+     * @param buffer ByteBuf where the value will be written
+     */
+    private static void writeShortest(final int value, final ByteBuf buffer) {
+        if (value <= Values.UNSIGNED_BYTE_MAX_VALUE) {
+            buffer.writeByte(UnsignedBytes.checkedCast(value));
+        } else if (value <= Values.UNSIGNED_SHORT_MAX_VALUE) {
+            ByteBufWriteUtil.writeUnsignedShort(value, buffer);
+        } else if (value <= Values.UNSIGNED_INT_MAX_VALUE) {
+            ByteBufWriteUtil.writeUnsignedInt(UnsignedInts.toLong(value), buffer);
+        } else {
+            buffer.writeLong(value);
+        }
+    }
+
+    private static void serializeNumericOperand(final NumericOperand op, final int length, final ByteBuf buffer) {
+        final BitSet bs = new BitSet(Byte.SIZE);
+        if (op.isEndOfList() != null) {
+            bs.set(END_OF_LIST, op.isEndOfList());
+        }
+        if (op.isAndBit() != null) {
+            bs.set(AND_BIT, op.isAndBit());
+        }
+        if (op.isLessThan() != null) {
+            bs.set(LESS_THAN, op.isLessThan());
+        }
+        if (op.isGreaterThan() != null) {
+            bs.set(GREATER_THAN, op.isGreaterThan());
+        }
+        if (op.isEquals() != null) {
+            bs.set(EQUAL, op.isEquals());
+        }
+        final byte len = (byte) (Integer.numberOfTrailingZeros(length) << LENGTH_SHIFT);
+        buffer.writeByte(bs.toByteArray()[0] | len);
+    }
+
+    private static void serializeBitmaskOperand(final BitmaskOperand op, final int length, final ByteBuf buffer) {
+        final BitSet bs = new BitSet(Byte.SIZE);
+        if (op.isEndOfList() != null) {
+            bs.set(END_OF_LIST, op.isEndOfList());
+        }
+        if (op.isAndBit() != null) {
+            bs.set(AND_BIT, op.isAndBit());
+        }
+        if (op.isMatch() != null) {
+            bs.set(MATCH, op.isMatch());
+        }
+        if (op.isNot() != null) {
+            bs.set(NOT, op.isNot());
+        }
+        final byte len = (byte) (Integer.numberOfTrailingZeros(length) << LENGTH_SHIFT);
+        buffer.writeByte(bs.toByteArray()[0] | len);
+    }
+
+    @Override
+    public void parseNlri(final ByteBuf nlri, final MpUnreachNlriBuilder builder) throws BGPParsingException {
+        if (!nlri.isReadable()) {
+            return;
+        }
+        final List<Flowspec> dst = parseNlri(nlri);
+
+        builder.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(
+            new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationFlowspecCaseBuilder().setDestinationFlowspec(
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.destination.flowspec._case.DestinationFlowspecBuilder().setFlowspec(
+                    dst).build()).build()).build());
+    }
+
+    @Override
+    public void parseNlri(final ByteBuf nlri, final MpReachNlriBuilder builder) throws BGPParsingException {
+        if (!nlri.isReadable()) {
+            return;
+        }
+        final List<Flowspec> dst = parseNlri(nlri);
+
+        builder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(
+            new DestinationFlowspecCaseBuilder().setDestinationFlowspec(new DestinationFlowspecBuilder().setFlowspec(dst).build()).build()).build());
+    }
+
+    public static List<Flowspec> parseNlri(final ByteBuf nlri) throws BGPParsingException {
+        if (!nlri.isReadable()) {
+            return null;
+        }
+        final List<Flowspec> fss = new ArrayList<>();
+
+        // length field can be one or two bytes (if needed)
+        // check the length of nlri to see how many bytes we can skip
+        final int length = nlri.readableBytes();
+        nlri.skipBytes(length > 240 ? NLRI_LENGTH_EXTENDED : NLRI_LENGTH);
+
+        while(nlri.isReadable()) {
+            final FlowspecBuilder builder = new FlowspecBuilder();
+            // read type
+            final ComponentType type = ComponentType.forValue(nlri.readUnsignedByte());
+            builder.setComponentType(type);
+            switch (type) {
+            case DestinationPrefix:
+                builder.setFlowspecType(new DestinationPrefixCaseBuilder().setDestinationPrefix(Ipv4Util.prefixForByteBuf(nlri)).build());
+                break;
+            case SourcePrefix:
+                builder.setFlowspecType(new SourcePrefixCaseBuilder().setSourcePrefix(Ipv4Util.prefixForByteBuf(nlri)).build());
+                break;
+            case ProtocolIp:
+                builder.setFlowspecType(new ProtocolIpCaseBuilder().setProtocolIps(parseProtocolIp(nlri)).build());
+                break;
+            case Port:
+                builder.setFlowspecType(new PortCaseBuilder().setPorts(parsePort(nlri)).build());
+                break;
+            case DestinationPort:
+                builder.setFlowspecType(new DestinationPortCaseBuilder().setDestinationPorts(parseDestinationPort(nlri)).build());
+                break;
+            case SourcePort:
+                builder.setFlowspecType(new SourcePortCaseBuilder().setSourcePorts(parseSourcePort(nlri)).build());
+                break;
+            case IcmpType:
+                builder.setFlowspecType(new IcmpTypeCaseBuilder().setTypes(parseIcmpType(nlri)).build());
+                break;
+            case IcmpCode:
+                builder.setFlowspecType(new IcmpCodeCaseBuilder().setCodes(parseIcmpCode(nlri)).build());
+                break;
+            case TcpFlags:
+                builder.setFlowspecType(new TcpFlagsCaseBuilder().setTcpFlags(parseTcpFlags(nlri)).build());
+                break;
+            case PacketLength:
+                builder.setFlowspecType(new PacketLengthCaseBuilder().setPacketLengths(parsePacketLength(nlri)).build());
+                break;
+            case Dscp:
+                builder.setFlowspecType(new DscpCaseBuilder().setDscps(parseDscp(nlri)).build());
+                break;
+            case Fragment:
+                builder.setFlowspecType(new FragmentCaseBuilder().setFragments(parseFragment(nlri)).build());
+                break;
+            default:
+                break;
+            }
+            fss.add(builder.build());
+        }
+        return fss;
+    }
+
+    private static List<ProtocolIps> parseProtocolIp(final ByteBuf nlri) {
+        final List<ProtocolIps> ips = new ArrayList<>();
+        boolean end = false;
+        // we can do this as all fields will be rewritten in the cycle
+        final ProtocolIpsBuilder builder = new ProtocolIpsBuilder();
+        while (!end) {
+            final byte b = nlri.readByte();
+            final NumericOperand op = parseNumeric(b);
+            builder.setOp(op);
+            final short length = parseLength(b);
+            builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
+            end = op.isEndOfList();
+            ips.add(builder.build());
+        }
+        return ips;
+    }
+
+    private static List<Ports> parsePort(final ByteBuf nlri) {
+        final List<Ports> ports = new ArrayList<>();
+        boolean end = false;
+        // we can do this as all fields will be rewritten in the cycle
+        final PortsBuilder builder = new PortsBuilder();
+        while (!end) {
+            final byte b = nlri.readByte();
+            final NumericOperand op = parseNumeric(b);
+            builder.setOp(op);
+            final short length = parseLength(b);
+            builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
+            end = op.isEndOfList();
+            ports.add(builder.build());
+        }
+        return ports;
+    }
+
+    private static List<DestinationPorts> parseDestinationPort(final ByteBuf nlri) {
+        final List<DestinationPorts> ports = new ArrayList<>();
+        boolean end = false;
+        // we can do this as all fields will be rewritten in the cycle
+        final DestinationPortsBuilder builder = new DestinationPortsBuilder();
+        while (!end) {
+            final byte b = nlri.readByte();
+            final NumericOperand op = parseNumeric(b);
+            builder.setOp(op);
+            final short length = parseLength(b);
+            builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
+            end = op.isEndOfList();
+            ports.add(builder.build());
+        }
+        return ports;
+    }
+
+    private static List<SourcePorts> parseSourcePort(final ByteBuf nlri) {
+        final List<SourcePorts> ports = new ArrayList<>();
+        boolean end = false;
+        // we can do this as all fields will be rewritten in the cycle
+        final SourcePortsBuilder builder = new SourcePortsBuilder();
+        while (!end) {
+            final byte b = nlri.readByte();
+            final NumericOperand op = parseNumeric(b);
+            builder.setOp(op);
+            final short length = parseLength(b);
+            builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
+            end = op.isEndOfList();
+            ports.add(builder.build());
+        }
+        return ports;
+    }
+
+    private static List<Types> parseIcmpType(final ByteBuf nlri) {
+        final List<Types> types = new ArrayList<>();
+        boolean end = false;
+        // we can do this as all fields will be rewritten in the cycle
+        final TypesBuilder builder = new TypesBuilder();
+        while (!end) {
+            final byte b = nlri.readByte();
+            final NumericOperand op = parseNumeric(b);
+            builder.setOp(op);
+            builder.setValue((short) UnsignedBytes.toInt((nlri.readByte())));
+            end = op.isEndOfList();
+            types.add(builder.build());
+        }
+        return types;
+    }
+
+    private static List<Codes> parseIcmpCode(final ByteBuf nlri) {
+        final List<Codes> codes = new ArrayList<>();
+        boolean end = false;
+        // we can do this as all fields will be rewritten in the cycle
+        final CodesBuilder builder = new CodesBuilder();
+        while (!end) {
+            final byte b = nlri.readByte();
+            final NumericOperand op = parseNumeric(b);
+            builder.setOp(op);
+            builder.setValue((short) UnsignedBytes.toInt((nlri.readByte())));
+            end = op.isEndOfList();
+            codes.add(builder.build());
+        }
+        return codes;
+    }
+
+    private static List<TcpFlags> parseTcpFlags(final ByteBuf nlri) {
+        final List<TcpFlags> flags = new ArrayList<>();
+        boolean end = false;
+        // we can do this as all fields will be rewritten in the cycle
+        final TcpFlagsBuilder builder = new TcpFlagsBuilder();
+        while (!end) {
+            final byte b = nlri.readByte();
+            final BitmaskOperand op = parseBitmask(b);
+            builder.setOp(op);
+            final short length = parseLength(b);
+            builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
+            end = op.isEndOfList();
+            flags.add(builder.build());
+        }
+        return flags;
+    }
+
+    private static List<PacketLengths> parsePacketLength(final ByteBuf nlri) {
+        final List<PacketLengths> plengths = new ArrayList<>();
+        boolean end = false;
+        // we can do this as all fields will be rewritten in the cycle
+        final PacketLengthsBuilder builder = new PacketLengthsBuilder();
+        while (!end) {
+            final byte b = nlri.readByte();
+            // RFC does not specify which operand to use
+            final NumericOperand op = parseNumeric(b);
+            builder.setOp(op);
+            final short length = parseLength(b);
+            builder.setValue(ByteArray.bytesToInt(ByteArray.readBytes(nlri, length)));
+            end = op.isEndOfList();
+            plengths.add(builder.build());
+        }
+        return plengths;
+    }
+
+    private static List<Dscps> parseDscp(final ByteBuf nlri) {
+        final List<Dscps> dscps = new ArrayList<>();
+        boolean end = false;
+        // we can do this as all fields will be rewritten in the cycle
+        final DscpsBuilder builder = new DscpsBuilder();
+        while (!end) {
+            final byte b = nlri.readByte();
+            // RFC does not specify operator
+            final NumericOperand op = parseNumeric(b);
+            builder.setOp(op);
+            builder.setValue(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.Dscp((short) UnsignedBytes.toInt((nlri.readByte()))));
+            end = op.isEndOfList();
+            dscps.add(builder.build());
+        }
+        return dscps;
+    }
+
+    private static List<Fragments> parseFragment(final ByteBuf nlri) {
+        final List<Fragments> fragments = new ArrayList<>();
+        boolean end = false;
+        // we can do this as all fields will be rewritten in the cycle
+        final FragmentsBuilder builder = new FragmentsBuilder();
+        while (!end) {
+            final byte b = nlri.readByte();
+            final BitmaskOperand op = parseBitmask(b);
+            builder.setOp(op);
+            builder.setValue(parseFragment(nlri.readByte()));
+            end = op.isEndOfList();
+            fragments.add(builder.build());
+        }
+        return fragments;
+    }
+
+    private static NumericOperand parseNumeric(final byte op) {
+        final BitSet bs = BitSet.valueOf(new long[] {UnsignedBytes.toInt(op)});
+        return new NumericOperand(bs.get(AND_BIT), bs.get(END_OF_LIST), bs.get(EQUAL), bs.get(GREATER_THAN), bs.get(LESS_THAN));
+    }
+
+    private static BitmaskOperand parseBitmask(final byte op) {
+        final BitSet bs = BitSet.valueOf(new long[] {UnsignedBytes.toInt(op)});
+        return new BitmaskOperand(bs.get(AND_BIT), bs.get(END_OF_LIST), bs.get(MATCH), bs.get(NOT));
+    }
+
+    @VisibleForTesting
+    public static short parseLength(final byte op) {
+        return (short) (1 << ((op & LENGTH_BITMASK) >> LENGTH_SHIFT));
+    }
+
+    private static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.Fragment parseFragment(final byte fragment) {
+        final BitSet bs = BitSet.valueOf(new long[] {UnsignedBytes.toInt(fragment)});
+        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));
+    }
+
+    private static byte serializeFragment(final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.Fragment fragment) {
+        final BitSet bs = new BitSet(Byte.SIZE);
+        if (fragment.isDoNot() != null) {
+            bs.set(DONT_FRAGMENT, fragment.isDoNot());
+        }
+        if (fragment.isFirst() != null) {
+            bs.set(FIRST_FRAGMENT, fragment.isFirst());
+        }
+        if (fragment.isIsA() != null) {
+            bs.set(IS_A_FRAGMENT, fragment.isIsA());
+        }
+        if (fragment.isLast() != null) {
+            bs.set(LAST_FRAGMENT, fragment.isLast());
+        }
+        return bs.toByteArray()[0];
+    }
+}
index 15867eedd70a454b8adce5f787bfe95addcc796a..b6f3f51f260eb065d68f23a321644ad48880e703 100644 (file)
@@ -200,99 +200,75 @@ module bgp-flowspec {
             }
             choice flowspec-type {
                 case destination-prefix-case {
-                    container destination-prefix {
-                        when "../component-type = destination-prefix";
-                        leaf destination-prefix {
-                            type inet:ipv4-prefix;
-                        }
+                    when "../component-type = destination-prefix";
+                    leaf destination-prefix {
+                        type inet:ipv4-prefix;
                     }
                 }
                 case source-prefix-case {
-                    container source-prefix {
-                        when "../component-type = source-prefix";
-                        leaf source-prefix {
-                            type inet:ipv4-prefix;
-                        }
+                    when "../component-type = source-prefix";
+                    leaf source-prefix {
+                        type inet:ipv4-prefix;
                     }
                 }
                 case protocol-ip-case {
-                    container protocol-ip {
-                        when "../component-type = protocol-ip";
-                        list protocol-ips {
-                            uses numeric-two-byte-value;
-                        }
+                    when "../component-type = protocol-ip";
+                    list protocol-ips {
+                        uses numeric-two-byte-value;
                     }
                 }
                 case port-case {
-                    container port {
-                        when "../component-type = port";
-                        list ports {
-                            uses numeric-two-byte-value;
-                        }
+                    when "../component-type = port";
+                    list ports {
+                        uses numeric-two-byte-value;
                     }
                 }
                 case destination-port-case {
-                    container destination-port {
-                        when "../component-type = destination-port";
-                        list destination-ports {
-                            uses numeric-two-byte-value;
-                        }
+                    when "../component-type = destination-port";
+                    list destination-ports {
+                        uses numeric-two-byte-value;
                     }
                 }
                 case source-port-case {
-                    container source-port {
-                        when "../component-type = source-port";
-                        list source-ports {
-                            uses numeric-two-byte-value;
-                        }
+                    when "../component-type = source-port";
+                    list source-ports {
+                        uses numeric-two-byte-value;
                     }
                 }
                 case icmp-type-case {
-                    container icmp-type {
-                        when "../component-type = icmp-type";
-                        list types {
-                            uses numeric-one-byte-value;
-                        }
+                    when "../component-type = icmp-type";
+                    list types {
+                        uses numeric-one-byte-value;
                     }
                 }
                 case icmp-code-case {
-                    container icmp-code {
-                        when "../component-type = icmp-code";
-                        list codes {
-                            uses numeric-one-byte-value;
-                        }
+                    when "../component-type = icmp-code";
+                    list codes {
+                        uses numeric-one-byte-value;
                     }
                 }
                 case tcp-flags-case {
-                    container tcp-flags {
-                        when "../component-type = tcp-flags";
-                        list tcp-flags {
-                            uses bitmask-two-byte-value;
-                        }
+                    when "../component-type = tcp-flags";
+                    list tcp-flags {
+                        uses bitmask-two-byte-value;
                     }
                 }
                 case packet-length-case {
-                    container packet-length {
-                        when "../component-type = packet-length";
-                        list packet-lengths {
-                            uses numeric-two-byte-value;
-                        }
+                    when "../component-type = packet-length";
+                    list packet-lengths {
+                        uses numeric-two-byte-value;
                     }
                 }
                 case dscp-case {
-                    container dscp {
-                        when "../component-type = dscp";
-                        list dscps {
-                            uses dscp-value;
-                        }
+                    when "../component-type = dscp";
+                    list dscps {
+                        uses dscp-value;
                     }
                 }
                 case fragment-case {
-                    container fragment {
-                        when "../component-type = fragment";
-                        list fragments {
-                            uses fragment-value;
-                        }
+                    when "../component-type = fragment";
+                    list fragments {
+                        uses fragment-value;
                     }
                 }
             }
diff --git a/bgp/flowspec/src/test/java/org/opendaylight/protocol/bgp/flowspec/FSNlriParserTest.java b/bgp/flowspec/src/test/java/org/opendaylight/protocol/bgp/flowspec/FSNlriParserTest.java
new file mode 100644 (file)
index 0000000..b256618
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.protocol.bgp.flowspec;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import com.google.common.collect.Lists;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+import org.opendaylight.protocol.bgp.parser.BGPParsingException;
+import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.ComponentType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.NumericOperand;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.Flowspec;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.FlowspecBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DestinationPrefixCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.DestinationPrefixCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.PortCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.PortCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.ProtocolIpCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.ProtocolIpCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.SourcePrefixCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.SourcePrefixCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.port._case.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.port._case.PortsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.protocol.ip._case.ProtocolIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.flowspec.destination.flowspec.flowspec.type.protocol.ip._case.ProtocolIpsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationFlowspecCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.destination.flowspec._case.DestinationFlowspecBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlriBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
+
+public class FSNlriParserTest {
+
+    private static final byte[] nlri = new byte[] { 0x13, 01, 0x18, 0x0a, 00, 01, 02, 0x08, (byte) 0xc0, 03, (byte) 0x81, 06, 04, 03, (byte) 0x89, 0x45, (byte) 0x8b, (byte) 0x91, 0x1f, (byte) 0x90 };
+
+    @Test
+    public void testParseLength() {
+        // 00-00-0000 = 1
+        assertEquals(1, FSNlriParser.parseLength((byte)0x00));
+        // 00-01-0000 = 2
+        assertEquals(2, FSNlriParser.parseLength((byte)16));
+        // 00-10-0000 = 4
+        assertEquals(4, FSNlriParser.parseLength((byte)32));
+        // 00-11-0000 = 8
+        assertEquals(8, FSNlriParser.parseLength((byte)48));
+    }
+
+
+    @Test
+    public void testParseNlri() throws BGPParsingException {
+        final List<Flowspec> fs = new ArrayList<>();
+        final MpReachNlriBuilder mp = new MpReachNlriBuilder();
+
+        final FlowspecBuilder builder = new FlowspecBuilder();
+        builder.setComponentType(ComponentType.DestinationPrefix);
+        final DestinationPrefixCase destinationPrefix = new DestinationPrefixCaseBuilder().setDestinationPrefix(new Ipv4Prefix("10.0.1.0/24")).build();
+        builder.setFlowspecType(destinationPrefix);
+        fs.add(builder.build());
+        builder.setComponentType(ComponentType.SourcePrefix);
+        final SourcePrefixCase sourcePrefix = new SourcePrefixCaseBuilder().setSourcePrefix(new Ipv4Prefix("192.0.0.0/8")).build();
+        builder.setFlowspecType(sourcePrefix);
+        fs.add(builder.build());
+
+        builder.setComponentType(ComponentType.ProtocolIp);
+        final List<ProtocolIps> protocols = Lists.newArrayList(new ProtocolIpsBuilder().setOp(new NumericOperand(false, true, true, false, false)).setValue(6).build());
+        final ProtocolIpCase prots = new ProtocolIpCaseBuilder().setProtocolIps(protocols).build();
+        builder.setFlowspecType(prots);
+        fs.add(builder.build());
+
+        builder.setComponentType(ComponentType.Port);
+        final List<Ports> ports = Lists.newArrayList(new PortsBuilder().setOp(new NumericOperand(false, false, true, true, false)).setValue(137).build(),
+            new PortsBuilder().setOp(new NumericOperand(true, false, true, false, true)).setValue(139).build(),
+            new PortsBuilder().setOp(new NumericOperand(false, true, true, false, false)).setValue(8080).build());
+        final PortCase ps = new PortCaseBuilder().setPorts(ports).build();
+        builder.setFlowspecType(ps);
+        fs.add(builder.build());
+
+        mp.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(new DestinationFlowspecCaseBuilder().setDestinationFlowspec(new DestinationFlowspecBuilder().setFlowspec(fs).build()).build()).build());
+
+        final FSNlriParser parser = new FSNlriParser();
+
+        final MpReachNlriBuilder result = new MpReachNlriBuilder();
+        parser.parseNlri(Unpooled.wrappedBuffer(nlri), result);
+
+        final List<Flowspec> flows = ((DestinationFlowspecCase)(result.getAdvertizedRoutes().getDestinationType())).getDestinationFlowspec().getFlowspec();
+        assertEquals(4, flows.size());
+        assertEquals(destinationPrefix, flows.get(0).getFlowspecType());
+        assertEquals(sourcePrefix, flows.get(1).getFlowspecType());
+        assertEquals(prots, flows.get(2).getFlowspecType());
+        assertEquals(ps, flows.get(3).getFlowspecType());
+
+        final ByteBuf buffer = Unpooled.buffer();
+        parser.serializeAttribute(new PathAttributesBuilder().addAugmentation(PathAttributes1.class, new PathAttributes1Builder().setMpReachNlri(mp.build()).build()).build(), buffer);
+        assertArrayEquals(nlri, ByteArray.readAllBytes(buffer));
+    }
+}
index 9561d2bfd71c57e47e618c3688e0a127b2180d22..2bf7e0bf203bb102f63a84442cde382d9d466544 100644 (file)
@@ -26,6 +26,11 @@ public final class Values {
      */
     public static final int UNSIGNED_BYTE_MAX_VALUE = 255;
 
+    /**
+     * Maximum unsigned Integer value (2147483648);
+     */
+    public static final long UNSIGNED_INT_MAX_VALUE = Integer.MAX_VALUE + 1;
+
     /**
      * Maximum unsigned Byte value in hex (0xFF).
      */