From 5699086233d34e1fb3310b64a17d8b09eb65df52 Mon Sep 17 00:00:00 2001 From: Dana Kutenicsova Date: Mon, 20 Apr 2015 16:34:41 +0200 Subject: [PATCH] BUG-2571 : created method for serializing FS NLRI to string We will use this string key as a list key in flowspec-routes. Change-Id: I5707e9f1ef2b999ad240af4a8e7a4d5c555aca44 Signed-off-by: Dana Kutenicsova --- .../protocol/bgp/flowspec/FSNlriParser.java | 234 ++++++++++++++++-- .../bgp/flowspec/FSNlriParserTest.java | 43 ++-- 2 files changed, 238 insertions(+), 39 deletions(-) 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 index d9e6a23123..3bb9743d75 100644 --- 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 @@ -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 flags = ((TcpFlagsCase)value).getTcpFlags(); + final List 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 = ((DscpCase)value).getDscps(); + final List 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 = ((FragmentCase)value).getFragments(); + final List 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 String stringNumericTwo(final List 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 stringNumericOne(final List 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 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) { + 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) { + 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(); + } } 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 index b25020444b..6cfc832ea0 100644 --- 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 @@ -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 fs = new ArrayList<>(); @@ -165,7 +164,7 @@ public class FSNlriParserTest { final MpReachNlriBuilder result = new MpReachNlriBuilder(); parser.parseNlri(Unpooled.wrappedBuffer(nlri), result); - final List flows = ((DestinationFlowspecCase)(result.getAdvertizedRoutes().getDestinationType())).getDestinationFlowspec().getFlowspec(); + final List 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 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 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 -- 2.36.6