BUG-2571 : created method for serializing FS NLRI to string 34/18634/8
authorDana Kutenicsova <dkutenic@cisco.com>
Mon, 20 Apr 2015 14:34:41 +0000 (16:34 +0200)
committerDana Kutenicsova <dkutenic@cisco.com>
Thu, 23 Apr 2015 07:12:38 +0000 (09:12 +0200)
We will use this string key as a list key in flowspec-routes.

Change-Id: I5707e9f1ef2b999ad240af4a8e7a4d5c555aca44
Signed-off-by: Dana Kutenicsova <dkutenic@cisco.com>
bgp/flowspec/src/main/java/org/opendaylight/protocol/bgp/flowspec/FSNlriParser.java
bgp/flowspec/src/test/java/org/opendaylight/protocol/bgp/flowspec/FSNlriParserTest.java

index d9e6a23123baa724266e6080c96ebc9f70fcea85..3bb9743d75bfd0b589befff5d1c2e9ef400c5f01 100644 (file)
@@ -95,8 +95,8 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -156,12 +156,8 @@ public class FSNlriParser implements NlriParser, NlriSerializer {
         final Attributes2 pathAttributes2 = pathAttributes.getAugmentation(Attributes2.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.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.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();
+            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) {
+                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();
                 serializeNlri(flowspecCase.getDestinationFlowspec().getFlowspec(), byteAggregator);
             }
         } else if (pathAttributes2 != null) {
@@ -214,31 +210,31 @@ public class FSNlriParser implements NlriParser, NlriSerializer {
             final FlowspecType value = flow.getFlowspecType();
             switch (flow.getComponentType()) {
             case DestinationPrefix:
-                nlriByteBuf.writeBytes(Ipv4Util.bytesForPrefixBegin(((DestinationPrefixCase)value).getDestinationPrefix()));
+                nlriByteBuf.writeBytes(Ipv4Util.bytesForPrefixBegin(((DestinationPrefixCase) value).getDestinationPrefix()));
                 break;
             case SourcePrefix:
-                nlriByteBuf.writeBytes(Ipv4Util.bytesForPrefixBegin(((SourcePrefixCase)value).getSourcePrefix()));
+                nlriByteBuf.writeBytes(Ipv4Util.bytesForPrefixBegin(((SourcePrefixCase) value).getSourcePrefix()));
                 break;
             case ProtocolIp:
-                serializeNumericTwoByteValue(((ProtocolIpCase)value).getProtocolIps(), nlriByteBuf);
+                serializeNumericTwoByteValue(((ProtocolIpCase) value).getProtocolIps(), nlriByteBuf);
                 break;
             case Port:
-                serializeNumericTwoByteValue(((PortCase)value).getPorts(), nlriByteBuf);
+                serializeNumericTwoByteValue(((PortCase) value).getPorts(), nlriByteBuf);
                 break;
             case DestinationPort:
-                serializeNumericTwoByteValue(((DestinationPortCase)value).getDestinationPorts(), nlriByteBuf);
+                serializeNumericTwoByteValue(((DestinationPortCase) value).getDestinationPorts(), nlriByteBuf);
                 break;
             case SourcePort:
-                serializeNumericTwoByteValue(((SourcePortCase)value).getSourcePorts(), nlriByteBuf);
+                serializeNumericTwoByteValue(((SourcePortCase) value).getSourcePorts(), nlriByteBuf);
                 break;
             case IcmpType:
-                serializeNumericOneByteValue(((IcmpTypeCase)value).getTypes(), nlriByteBuf);
+                serializeNumericOneByteValue(((IcmpTypeCase) value).getTypes(), nlriByteBuf);
                 break;
             case IcmpCode:
-                serializeNumericOneByteValue(((IcmpCodeCase)value).getCodes(), nlriByteBuf);
+                serializeNumericOneByteValue(((IcmpCodeCase) value).getCodes(), nlriByteBuf);
                 break;
             case TcpFlags:
-                final List<TcpFlags> flags = ((TcpFlagsCase)value).getTcpFlags();
+                final List<TcpFlags> flags = ((TcpFlagsCase) value).getTcpFlags();
                 for (final TcpFlags flag : flags) {
                     final ByteBuf flagsBuf = Unpooled.buffer();
                     writeShortest(flag.getValue(), flagsBuf);
@@ -247,17 +243,17 @@ public class FSNlriParser implements NlriParser, NlriSerializer {
                 }
                 break;
             case PacketLength:
-                serializeNumericTwoByteValue(((PacketLengthCase)value).getPacketLengths(), nlriByteBuf);
+                serializeNumericTwoByteValue(((PacketLengthCase) value).getPacketLengths(), nlriByteBuf);
                 break;
             case Dscp:
-                final List<Dscps> dscps = ((DscpCase)value).getDscps();
+                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();
+                final List<Fragments> fragments = ((FragmentCase) value).getFragments();
                 for (final Fragments fragment : fragments) {
                     serializeBitmaskOperand(fragment.getOp(), 1, nlriByteBuf);
                     nlriByteBuf.writeByte(serializeFragment(fragment.getValue()));
@@ -340,7 +336,8 @@ public class FSNlriParser implements NlriParser, NlriSerializer {
 
         builder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(
             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()
-                .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().setFlowspec(dst).build()).build()).build());
+                .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()
+                    .setFlowspec(dst).build()).build()).build());
     }
 
     /**
@@ -360,7 +357,7 @@ public class FSNlriParser implements NlriParser, NlriSerializer {
         final int length = nlri.readableBytes();
         nlri.skipBytes(length > MAX_NLRI_LENGTH_ONE_BYTE ? NLRI_LENGTH_EXTENDED : NLRI_LENGTH);
 
-        while(nlri.isReadable()) {
+        while (nlri.isReadable()) {
             final FlowspecBuilder builder = new FlowspecBuilder();
             // read type
             final ComponentType type = ComponentType.forValue(nlri.readUnsignedByte());
@@ -607,9 +604,8 @@ public class FSNlriParser implements NlriParser, NlriSerializer {
         return bs.toByte();
     }
 
-    public static String stringNlri(final UnkeyedListEntryNode linkstate) {
-        // FIXME: BUG-2571 : create human-readable route key, e.g : "all packets to 10.0.1/24 from 192/8 and port {range [137, 139] or 8080}"
-        return "";
+    public static String stringNlri(final DataContainerNode<?> flowspec) {
+        return stringNlri(extractFlowspec((MapEntryNode) flowspec));
     }
 
     public static Flowspec extractFlowspec(final MapEntryNode route) {
@@ -690,4 +686,194 @@ public class FSNlriParser implements NlriParser, NlriSerializer {
             return null;
         }
     }
+
+    @VisibleForTesting
+    static final String stringNlri(final Flowspec flow) {
+        final StringBuilder buffer = new StringBuilder("all packets ");
+        final FlowspecType value = flow.getFlowspecType();
+        switch (flow.getComponentType()) {
+        case DestinationPrefix:
+            buffer.append("to ");
+            buffer.append(((DestinationPrefixCase) value).getDestinationPrefix().getValue());
+            break;
+        case SourcePrefix:
+            buffer.append("from ");
+            buffer.append(((SourcePrefixCase) value).getSourcePrefix().getValue());
+            break;
+        case ProtocolIp:
+            buffer.append("where protocol ");
+            buffer.append(stringNumericTwo(((ProtocolIpCase) value).getProtocolIps()));
+            break;
+        case Port:
+            buffer.append("where port ");
+            buffer.append(stringNumericTwo(((PortCase) value).getPorts()));
+            break;
+        case DestinationPort:
+            buffer.append("where destination port ");
+            buffer.append(stringNumericTwo(((DestinationPortCase) value).getDestinationPorts()));
+            break;
+        case SourcePort:
+            buffer.append("where source port ");
+            buffer.append(stringNumericTwo(((SourcePortCase) value).getSourcePorts()));
+            break;
+        case IcmpType:
+            buffer.append("where ICMP type ");
+            buffer.append(stringNumericOne(((IcmpTypeCase) value).getTypes()));
+            break;
+        case IcmpCode:
+            buffer.append("where ICMP code ");
+            buffer.append(stringNumericOne(((IcmpCodeCase) value).getCodes()));
+            break;
+        case TcpFlags:
+            buffer.append(stringTcpFlags(((TcpFlagsCase) value).getTcpFlags()));
+            break;
+        case PacketLength:
+            buffer.append("where packet length ");
+            buffer.append(stringNumericTwo(((PacketLengthCase) value).getPacketLengths()));
+            break;
+        case Dscp:
+            buffer.append(stringDscp(((DscpCase) value).getDscps()));
+            break;
+        case Fragment:
+            buffer.append(stringFragment(((FragmentCase) value).getFragments()));
+            break;
+        default:
+            LOG.warn("Skipping unhandled component type {}" , flow.getComponentType());
+            break;
+        }
+        return buffer.toString();
+    }
+
+    private static <T extends NumericTwoByteValue> String stringNumericTwo(final List<T> list) {
+        final StringBuilder buffer = new StringBuilder();
+        boolean isFirst = true;
+        for (final T item : list) {
+            buffer.append(stringNumericOperand(item.getOp(), isFirst));
+            buffer.append(item.getValue());
+            buffer.append(' ');
+            if (isFirst) {
+                isFirst = false;
+            }
+        }
+        return buffer.toString();
+    }
+
+    private static <T extends NumericOneByteValue> String stringNumericOne(final List<T> list) {
+        final StringBuilder buffer = new StringBuilder();
+        boolean isFirst = true;
+        for (final T item : list) {
+            buffer.append(stringNumericOperand(item.getOp(), isFirst));
+            buffer.append(item.getValue());
+            buffer.append(' ');
+            if (isFirst) {
+                isFirst = false;
+            }
+        }
+        return buffer.toString();
+    }
+
+    private static String stringNumericOperand(final NumericOperand op, final boolean isFirst) {
+        final StringBuilder buffer = new StringBuilder();
+        if (!op.isAndBit() && !isFirst) {
+            buffer.append("or ");
+        }
+        if (op.isAndBit()) {
+            buffer.append("and ");
+        }
+        if (op.isLessThan() && op.isEquals()) {
+            buffer.append("is less than or equal to ");
+            return buffer.toString();
+        } else if (op.isGreaterThan() && op.isEquals()) {
+            buffer.append("is greater than or equal to ");
+            return buffer.toString();
+        }
+        if (op.isEquals()) {
+            buffer.append("equals to ");
+        }
+        if (op.isLessThan()) {
+            buffer.append("is less than ");
+        }
+        if (op.isGreaterThan()) {
+            buffer.append("is greater than ");
+        }
+        return buffer.toString();
+    }
+
+    private static String stringTcpFlags(final List<TcpFlags> flags) {
+        final StringBuilder buffer = new StringBuilder("where TCP flags ");
+        boolean isFirst = true;
+        for (final TcpFlags item : flags) {
+            buffer.append(stringBitmaskOperand(item.getOp(), isFirst));
+            buffer.append(item.getValue());
+            buffer.append(' ');
+            if (isFirst) {
+                isFirst = false;
+            }
+        }
+        return buffer.toString();
+    }
+
+    private static String stringBitmaskOperand(final BitmaskOperand op, final boolean isFirst) {
+        final StringBuilder buffer = new StringBuilder();
+        if (!op.isAndBit() && !isFirst) {
+            buffer.append("or ");
+        }
+        if (op.isAndBit()) {
+            buffer.append("and ");
+        }
+        if (op.isMatch()) {
+            buffer.append("does ");
+            if (op.isNot()) {
+                buffer.append("not ");
+            }
+            buffer.append("match ");
+        } else if (op.isNot()) {
+            buffer.append("is not ");
+        }
+        return buffer.toString();
+    }
+
+    private static String stringDscp(final List<Dscps> dscps) {
+        final StringBuilder buffer = new StringBuilder("where DSCP ");
+        boolean isFirst = true;
+        for (final Dscps item : dscps) {
+            buffer.append(stringNumericOperand(item.getOp(), isFirst));
+            buffer.append(item.getValue().getValue());
+            buffer.append(' ');
+            if (isFirst) {
+                isFirst = false;
+            }
+        }
+        return buffer.toString();
+    }
+
+    private static String stringFragment(final List<Fragments> fragments) {
+        final StringBuilder buffer = new StringBuilder("where fragment ");
+        boolean isFirst = true;
+        for (final Fragments item : fragments) {
+            buffer.append(stringBitmaskOperand(item.getOp(), isFirst));
+            buffer.append(stringFragment(item.getValue()));
+            if (isFirst) {
+                isFirst = false;
+            }
+        }
+        return buffer.toString();
+    }
+
+    private static String stringFragment(final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.Fragment fragment) {
+        final StringBuilder buffer = new StringBuilder();
+        if (fragment.isDoNot()) {
+            buffer.append("'DO NOT' ");
+        }
+        if (fragment.isFirst()) {
+            buffer.append("'IS FIRST' ");
+        }
+        if (fragment.isLast()) {
+            buffer.append("'IS LAST' ");
+        }
+        if (fragment.isIsA()) {
+            buffer.append("'IS A' ");
+        }
+        return buffer.toString();
+    }
 }
index b25020444baa160479b7ad037c3099bf192d8ddd..6cfc832ea0d3cee5577696020086f3290d15b045 100644 (file)
@@ -93,29 +93,28 @@ public class FSNlriParserTest {
 
     private static final byte[] nlri = new byte[] { 0x1D, 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,
-        05, 0x12, 0x0f, (byte)0xf9, (byte)0x81, (byte)0xb3,
-        06, (byte) 0x91, 0x1f, (byte)0x90};
+        05, 0x12, 0x0f, (byte) 0xf9, (byte) 0x81, (byte) 0xb3,
+        06, (byte) 0x91, 0x1f, (byte) 0x90 };
 
-    private static final byte[] unnlri = new byte[] { 0x1B, 07, 4, 2, (byte)0x84, 3,
-        0x08, 06, 04, (byte)0x80, 05,
-        0x09, 0x12, 04, 01, (byte)0x91, 0x56, (byte) 0xb1,
-        0x0a, (byte)0x96, (byte) 0xde, (byte) 0xad,
-        0x0b, (byte)0x86, 0x2a,
-        0x0c, (byte)0x81, (byte)0x0f};
+    private static final byte[] unnlri = new byte[] { 0x1B, 07, 4, 2, (byte) 0x84, 3,
+        0x08, 06, 04, (byte) 0x80, 05,
+        0x09, 0x12, 04, 01, (byte) 0x91, 0x56, (byte) 0xb1,
+        0x0a, (byte) 0x96, (byte) 0xde, (byte) 0xad,
+        0x0b, (byte) 0x86, 0x2a,
+        0x0c, (byte) 0x81, (byte) 0x0f };
 
     @Test
     public void testParseLength() {
         // 00-00-0000 = 1
-        assertEquals(1, FSNlriParser.parseLength((byte)0x00));
+        assertEquals(1, FSNlriParser.parseLength((byte) 0x00));
         // 00-01-0000 = 2
-        assertEquals(2, FSNlriParser.parseLength((byte)16));
+        assertEquals(2, FSNlriParser.parseLength((byte) 16));
         // 00-10-0000 = 4
-        assertEquals(4, FSNlriParser.parseLength((byte)32));
+        assertEquals(4, FSNlriParser.parseLength((byte) 32));
         // 00-11-0000 = 8
-        assertEquals(8, FSNlriParser.parseLength((byte)48));
+        assertEquals(8, FSNlriParser.parseLength((byte) 48));
     }
 
-
     @Test
     public void testParseMpReachNlri() throws BGPParsingException {
         final List<Flowspec> fs = new ArrayList<>();
@@ -165,7 +164,7 @@ public class FSNlriParserTest {
         final MpReachNlriBuilder result = new MpReachNlriBuilder();
         parser.parseNlri(Unpooled.wrappedBuffer(nlri), result);
 
-        final List<Flowspec> flows = ((DestinationFlowspecCase)(result.getAdvertizedRoutes().getDestinationType())).getDestinationFlowspec().getFlowspec();
+        final List<Flowspec> flows = ((DestinationFlowspecCase) (result.getAdvertizedRoutes().getDestinationType())).getDestinationFlowspec().getFlowspec();
         assertEquals(6, flows.size());
         assertEquals(destinationPrefix, flows.get(0).getFlowspecType());
         assertEquals(sourcePrefix, flows.get(1).getFlowspecType());
@@ -177,6 +176,13 @@ public class FSNlriParserTest {
         final ByteBuf buffer = Unpooled.buffer();
         parser.serializeAttribute(new AttributesBuilder().addAugmentation(Attributes1.class, new Attributes1Builder().setMpReachNlri(mp.build()).build()).build(), buffer);
         assertArrayEquals(nlri, ByteArray.readAllBytes(buffer));
+
+        assertEquals("all packets to 10.0.1.0/24", FSNlriParser.stringNlri(flows.get(0)));
+        assertEquals("all packets from 192.0.0.0/8", FSNlriParser.stringNlri(flows.get(1)));
+        assertEquals("all packets where protocol equals to 6 ", FSNlriParser.stringNlri(flows.get(2)));
+        assertEquals("all packets where port is greater than or equal to 137 and is less than or equal to 139 or equals to 8080 ", FSNlriParser.stringNlri(flows.get(3)));
+        assertEquals("all packets where destination port is greater than 4089 or equals to 179 ", FSNlriParser.stringNlri(flows.get(4)));
+        assertEquals("all packets where source port equals to 8080 ", FSNlriParser.stringNlri(flows.get(5)));
     }
 
     @Test
@@ -234,7 +240,7 @@ public class FSNlriParserTest {
         final MpUnreachNlriBuilder result = new MpUnreachNlriBuilder();
         parser.parseNlri(Unpooled.wrappedBuffer(unnlri), result);
 
-        final List<Flowspec> flows = ((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationFlowspecCase)(result.getWithdrawnRoutes().getDestinationType())).getDestinationFlowspec().getFlowspec();
+        final List<Flowspec> flows = ((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.flowspec.rev150114.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationFlowspecCase) (result.getWithdrawnRoutes().getDestinationType())).getDestinationFlowspec().getFlowspec();
         assertEquals(6, flows.size());
         assertEquals(icmpType, flows.get(0).getFlowspecType());
         assertEquals(icmpCode, flows.get(1).getFlowspecType());
@@ -246,6 +252,13 @@ public class FSNlriParserTest {
         final ByteBuf buffer = Unpooled.buffer();
         parser.serializeAttribute(new AttributesBuilder().addAugmentation(Attributes2.class, new Attributes2Builder().setMpUnreachNlri(mp.build()).build()).build(), buffer);
         assertArrayEquals(unnlri, ByteArray.readAllBytes(buffer));
+
+        assertEquals("all packets where ICMP type is less than 2 or is less than 3 ", FSNlriParser.stringNlri(flows.get(0)));
+        assertEquals("all packets where ICMP code is less than is greater than 4 or 5 ", FSNlriParser.stringNlri(flows.get(1)));
+        assertEquals("all packets where TCP flags is not 1025 or does match 22193 ", FSNlriParser.stringNlri(flows.get(2)));
+        assertEquals("all packets where packet length is less than is greater than 57005 ", FSNlriParser.stringNlri(flows.get(3)));
+        assertEquals("all packets where DSCP is less than is greater than 42 ", FSNlriParser.stringNlri(flows.get(4)));
+        assertEquals("all packets where fragment does match 'DO NOT' 'IS FIRST' 'IS LAST' 'IS A' ", FSNlriParser.stringNlri(flows.get(5)));
     }
 
     @Test