Merge "Support proper route redistribution"
authorDana Kutenicsova <dkutenic@cisco.com>
Thu, 5 Mar 2015 12:37:00 +0000 (12:37 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 5 Mar 2015 12:37:00 +0000 (12:37 +0000)
85 files changed:
bgp/flowspec/src/main/java/org/opendaylight/protocol/bgp/flowspec/FSExtendedCommunitiesAttributeParser.java
bgp/flowspec/src/main/java/org/opendaylight/protocol/bgp/flowspec/FSNlriParser.java
bgp/flowspec/src/test/java/org/opendaylight/protocol/bgp/flowspec/FSNlriParserTest.java
bgp/linkstate/src/main/java/org/opendaylight/protocol/bgp/linkstate/attribute/LinkAttributesParser.java
bgp/linkstate/src/main/java/org/opendaylight/protocol/bgp/linkstate/attribute/NodeAttributesParser.java
bgp/linkstate/src/main/java/org/opendaylight/protocol/bgp/linkstate/attribute/PrefixAttributesParser.java
bgp/linkstate/src/main/java/org/opendaylight/protocol/bgp/linkstate/attribute/sr/SrLinkAttributesParser.java
bgp/linkstate/src/main/java/org/opendaylight/protocol/bgp/linkstate/attribute/sr/SrNodeAttributesParser.java
bgp/linkstate/src/main/java/org/opendaylight/protocol/bgp/linkstate/attribute/sr/SrPrefixAttributesParser.java
bgp/linkstate/src/main/java/org/opendaylight/protocol/bgp/linkstate/spi/TlvUtil.java
bgp/parser-spi/src/main/java/org/opendaylight/protocol/bgp/parser/spi/pojo/SimpleAttributeRegistry.java
bgp/rib-api/src/main/yang/bgp-rib.yang
bgp/rib-impl/pom.xml
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AbstractExportPolicy.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AbstractIPRIBSupport.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AbstractImportPolicy.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibInWriter.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibOutListener.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPSessionImpl.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BestPath.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BestPathSelector.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BestPathState.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/ChannelOutputLimiter.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/EffectiveRibInWriter.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/IPv4RIBSupport.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/IPv6RIBSupport.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/LocRibWriter.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/OffsetMap.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RouteEntry.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RouteUpdateKey.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RouterIds.java [new file with mode: 0644]
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/SessionRIBsOut.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/TableContext.java [new file with mode: 0644]
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/ApplicationPeerTest.java
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/SpeakerSessionMock.java
bgp/rib-spi/pom.xml
bgp/rib-spi/src/main/java/org/opendaylight/controller/config/yang/bgp/rib/spi/AbstractRIBSupport.java [new file with mode: 0644]
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/AbstractRIBSupportRegistration.java [new file with mode: 0644]
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/RIBExtensionConsumerContext.java
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/RIBExtensionProviderContext.java
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/RIBSupport.java [new file with mode: 0644]
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/RIBSupportRegistration.java [new file with mode: 0644]
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/SimpleRIBExtensionProviderContext.java
features/bgp/src/main/features/features.xml
integration-tests/src/test/java/org/opendaylight/protocol/integration/pcep/AbstractPcepOsgiTest.java
parent/pom.xml
pcep/ietf-stateful07/src/main/java/org/opendaylight/protocol/pcep/ietf/initiated00/CInitiated00LspObjectParser.java
pcep/ietf-stateful07/src/main/java/org/opendaylight/protocol/pcep/ietf/initiated00/CInitiated00SrpObjectParser.java
pcep/ietf-stateful07/src/main/java/org/opendaylight/protocol/pcep/ietf/initiated00/CInitiated00StatefulCapabilityTlvParser.java
pcep/ietf-stateful07/src/main/java/org/opendaylight/protocol/pcep/ietf/stateful07/Stateful07LspObjectParser.java
pcep/ietf-stateful07/src/main/java/org/opendaylight/protocol/pcep/ietf/stateful07/Stateful07RSVPErrorSpecTlvParser.java
pcep/ietf-stateful07/src/main/java/org/opendaylight/protocol/pcep/ietf/stateful07/Stateful07SrpObjectParser.java
pcep/ietf-stateful07/src/main/java/org/opendaylight/protocol/pcep/ietf/stateful07/Stateful07StatefulCapabilityTlvParser.java
pcep/ietf-stateful07/src/test/java/org/opendaylight/protocol/pcep/ietf/PCEPObjectParserTest.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/PCEPByteToMessageDecoder.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/object/PCEPCloseObjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/object/PCEPErrorObjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/object/PCEPExcludeRouteObjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/object/PCEPLoadBalancingObjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/object/PCEPLspaObjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/object/PCEPMetricObjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/object/PCEPMonitoringObjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/object/PCEPNoPathObjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/object/PCEPNotificationObjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/object/PCEPProcTimeObjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/object/PCEPRequestParameterObjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/object/PCEPSvecObjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/subobject/EROLabelSubobjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/subobject/EROUnnumberedInterfaceSubobjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/subobject/RROIpv4PrefixSubobjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/subobject/RROIpv6PrefixSubobjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/subobject/RROLabelSubobjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/subobject/RROUnnumberedInterfaceSubobjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/subobject/XROIpv4PrefixSubobjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/subobject/XROIpv6PrefixSubobjectParser.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/tlv/NoPathVectorTlvParser.java
pcep/segment-routing/src/main/java/org/opendaylight/protocol/pcep/segment/routing/SrEroSubobjectParser.java
pcep/segment-routing/src/main/java/org/opendaylight/protocol/pcep/segment/routing/SrRroSubobjectParser.java
pcep/segment-routing/src/main/java/org/opendaylight/protocol/pcep/segment/routing/SrSubobjectParserUtil.java
pcep/spi/src/main/java/org/opendaylight/protocol/pcep/spi/AbstractMessageParser.java
pcep/spi/src/main/java/org/opendaylight/protocol/pcep/spi/LabelUtil.java
pcep/spi/src/main/java/org/opendaylight/protocol/pcep/spi/ObjectUtil.java
util/src/main/java/org/opendaylight/protocol/util/BitArray.java [new file with mode: 0644]
util/src/main/java/org/opendaylight/protocol/util/ByteArray.java
util/src/test/java/org/opendaylight/protocol/util/BitArrayTest.java [new file with mode: 0644]

index d62d3f99c3dd270484708cb80f2840afa477d16d..613f6079429785aad003e2eb1d0a411a457e9100 100644 (file)
@@ -8,10 +8,10 @@
 package org.opendaylight.protocol.bgp.flowspec;
 
 import io.netty.buffer.ByteBuf;
-import java.util.BitSet;
 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
 import org.opendaylight.protocol.bgp.parser.BGPError;
 import org.opendaylight.protocol.bgp.parser.impl.message.update.ExtendedCommunitiesAttributeParser;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.ByteArray;
 import org.opendaylight.protocol.util.ByteBufWriteUtil;
 import org.opendaylight.protocol.util.ReferenceCache;
@@ -58,7 +58,7 @@ public class FSExtendedCommunitiesAttributeParser extends ExtendedCommunitiesAtt
 
     private static final int RESERVED = 5;
 
-    private static final int FLAGS_SIZE = 1;
+    private static final int FLAGS_SIZE = 8;
 
     private static final int SAMPLE_BIT = 6;
 
@@ -80,7 +80,7 @@ public class FSExtendedCommunitiesAttributeParser extends ExtendedCommunitiesAtt
                 break;
             case TRAFFIC_ACTION_SUBTYPE:
                 buffer.skipBytes(RESERVED);
-                final BitSet flags = ByteArray.bytesToBitSet(ByteArray.readBytes(buffer, FLAGS_SIZE));
+                final BitArray flags = BitArray.valueOf(buffer, FLAGS_SIZE);
                 final boolean sample = flags.get(SAMPLE_BIT);
                 final boolean terminal = flags.get(TERMINAL_BIT);
                 c = new TrafficActionExtendedCommunityCaseBuilder().setTrafficActionExtendedCommunity(new TrafficActionExtendedCommunityBuilder().setSample(sample).setTerminalAction(terminal).build()).build();
@@ -117,14 +117,10 @@ public class FSExtendedCommunitiesAttributeParser extends ExtendedCommunitiesAtt
         else if (ex instanceof TrafficActionExtendedCommunityCase) {
             final TrafficActionExtendedCommunity trafficAction = ((TrafficActionExtendedCommunityCase) ex).getTrafficActionExtendedCommunity();
             buffer.writeZero(RESERVED);
-            final BitSet flags = new BitSet(FLAGS_SIZE);
-            if (trafficAction.isSample() != null) {
-                flags.set(SAMPLE_BIT, trafficAction.isSample());
-            }
-            if (trafficAction.isTerminalAction() != null) {
-                flags.set(TERMINAL_BIT, trafficAction.isTerminalAction());
-            }
-            ByteBufWriteUtil.writeBitSet(flags, FLAGS_SIZE, buffer);
+            final BitArray flags = new BitArray(FLAGS_SIZE);
+            flags.set(SAMPLE_BIT, trafficAction.isSample());
+            flags.set(TERMINAL_BIT, trafficAction.isTerminalAction());
+            flags.toByteBuf(buffer);
         }
         else if (ex instanceof RedirectExtendedCommunityCase) {
             final RedirectExtendedCommunity redirect = ((RedirectExtendedCommunityCase) ex).getRedirectExtendedCommunity();
index 4f5c372334b988394be89a2ed2148d3a366c16cf..3910e4364e0a860ca5eedb8d85a6d6fc11bdce43 100644 (file)
@@ -14,11 +14,11 @@ 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.BitArray;
 import org.opendaylight.protocol.util.ByteArray;
 import org.opendaylight.protocol.util.ByteBufWriteUtil;
 import org.opendaylight.protocol.util.Ipv4Util;
@@ -101,21 +101,23 @@ public class FSNlriParser implements NlriParser, NlriSerializer {
      */
     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 OPERAND_LENGTH = 8;
+
+    private static final int END_OF_LIST = 0;
+    private static final int AND_BIT = 1;
     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 LESS_THAN = 5;
+    private static final int GREATER_THAN = 6;
+    private static final int EQUAL = 7;
 
-    private static final int NOT = 1;
-    private static final int MATCH = 0;
+    private static final int NOT = 6;
+    private static final int MATCH = 7;
 
-    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 LAST_FRAGMENT = 4;
+    private static final int FIRST_FRAGMENT = 5;
+    private static final int IS_A_FRAGMENT = 6;
+    private static final int DONT_FRAGMENT = 7;
 
     private static final int MAX_NLRI_LENGTH = 4095;
     private static final int MAX_NLRI_LENGTH_ONE_BYTE = 240;
@@ -269,42 +271,24 @@ public class FSNlriParser implements NlriParser, NlriSerializer {
     }
 
     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 BitArray bs = new BitArray(OPERAND_LENGTH);
+        bs.set(END_OF_LIST, op.isEndOfList());
+        bs.set(AND_BIT, op.isAndBit());
+        bs.set(LESS_THAN, op.isLessThan());
+        bs.set(GREATER_THAN, op.isGreaterThan());
+        bs.set(EQUAL, op.isEquals());
         final byte len = (byte) (Integer.numberOfTrailingZeros(length) << LENGTH_SHIFT);
-        buffer.writeByte(bs.toByteArray()[0] | len);
+        buffer.writeByte(bs.toByte() | 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 BitArray bs = new BitArray(OPERAND_LENGTH);
+        bs.set(END_OF_LIST, op.isEndOfList());
+        bs.set(AND_BIT, op.isAndBit());
+        bs.set(MATCH, op.isMatch());
+        bs.set(NOT, op.isNot());
         final byte len = (byte) (Integer.numberOfTrailingZeros(length) << LENGTH_SHIFT);
-        buffer.writeByte(bs.toByteArray()[0] | len);
+        buffer.writeByte(bs.toByte() | len);
     }
 
     @Override
@@ -562,12 +546,12 @@ public class FSNlriParser implements NlriParser, NlriSerializer {
     }
 
     private static NumericOperand parseNumeric(final byte op) {
-        final BitSet bs = BitSet.valueOf(new long[] {UnsignedBytes.toInt(op)});
+        final BitArray bs = BitArray.valueOf(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)});
+        final BitArray bs = BitArray.valueOf(op);
         return new BitmaskOperand(bs.get(AND_BIT), bs.get(END_OF_LIST), bs.get(MATCH), bs.get(NOT));
     }
 
@@ -577,24 +561,16 @@ public class FSNlriParser implements NlriParser, NlriSerializer {
     }
 
     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)});
+        final BitArray bs = BitArray.valueOf(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];
+        final BitArray bs = new BitArray(Byte.SIZE);
+        bs.set(DONT_FRAGMENT, fragment.isDoNot());
+        bs.set(FIRST_FRAGMENT, fragment.isFirst());
+        bs.set(IS_A_FRAGMENT, fragment.isIsA());
+        bs.set(LAST_FRAGMENT, fragment.isLast());
+        return bs.toByte();
     }
 }
index fb7e7e9c26cf2a909436b5c19146962b30a123ac..56f6390a25571f5aab372e8be185e20ba28b3c30 100644 (file)
@@ -95,7 +95,7 @@ public class FSNlriParserTest {
         0x09, 0x12, 04, 01, (byte)0x91, 0x56, (byte) 0xb1,
         0x0a, (byte)0x96, (byte) 0xde, (byte) 0xad,
         0x0b, (byte)0x86, 0x2a,
-        0x0c, (byte)0x81, (byte)0xf0};
+        0x0c, (byte)0x81, (byte)0x0f};
 
     @Test
     public void testParseLength() {
index e10b832b93da413e1b40bc0b63a35b506962b67b..04eb63de455df428769940a040c23458a7c03781 100644 (file)
@@ -15,11 +15,11 @@ import io.netty.buffer.ByteBufUtil;
 import io.netty.buffer.Unpooled;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.BitSet;
 import java.util.List;
 import java.util.Map.Entry;
 import org.opendaylight.protocol.bgp.linkstate.attribute.sr.SrLinkAttributesParser;
 import org.opendaylight.protocol.bgp.linkstate.spi.TlvUtil;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.ByteArray;
 import org.opendaylight.protocol.util.Ipv4Util;
 import org.opendaylight.protocol.util.Ipv6Util;
@@ -58,8 +58,10 @@ public final class LinkAttributesParser {
     private static final int BANDWIDTH_LENGTH = 4;
 
     // MPLS protection mask bits
-    private static final int LDP_BIT = 7;
-    private static final int RSVP_BIT = 6;
+    private static final int FLAGS_SIZE = 8;
+
+    private static final int LDP_BIT = 0;
+    private static final int RSVP_BIT = 1;
 
     /* Link Attribute TLVs */
     private static final int REMOTE_IPV4_ROUTER_ID = 1030;
@@ -147,7 +149,7 @@ public final class LinkAttributesParser {
                 LOG.debug("Parsed Link Protection Type {}", lpt);
                 break;
             case MPLS_PROTOCOL:
-                final BitSet bits = BitSet.valueOf(ByteArray.readAllBytes(value));
+                final BitArray bits = BitArray.valueOf(value, FLAGS_SIZE);
                 builder.setMplsProtocol(new MplsProtocolMask(bits.get(LDP_BIT), bits.get(RSVP_BIT)));
                 LOG.debug("Parsed MPLS Protocols: {}", builder.getMplsProtocol());
                 break;
@@ -255,14 +257,10 @@ public final class LinkAttributesParser {
     private static void serializeMplsProtocolMask(final MplsProtocolMask mplsProtocolMask, final ByteBuf byteAggregator ) {
         if (mplsProtocolMask != null) {
             final ByteBuf mplsProtocolMaskBuf = Unpooled.buffer(1);
-            final BitSet mask = new BitSet(Byte.SIZE);
-            if (mplsProtocolMask.isLdp() != null) {
-                mask.set(LDP_BIT, mplsProtocolMask.isLdp());
-            }
-            if (mplsProtocolMask.isRsvpte() != null) {
-                mask.set(RSVP_BIT, mplsProtocolMask.isRsvpte());
-            }
-            mplsProtocolMaskBuf.writeBytes(mask.toByteArray());
+            final BitArray mask = new BitArray(FLAGS_SIZE);
+            mask.set(LDP_BIT, mplsProtocolMask.isLdp());
+            mask.set(RSVP_BIT, mplsProtocolMask.isRsvpte());
+            mask.toByteBuf(mplsProtocolMaskBuf);
             TlvUtil.writeTLV(MPLS_PROTOCOL, mplsProtocolMaskBuf, byteAggregator);
         }
     }
index 841cc46a6cd933c189b347f59f8b136da8bbd965..f2e15c671331efe5584e040f883fbf60c5291965 100644 (file)
@@ -14,11 +14,11 @@ import io.netty.buffer.ByteBuf;
 import io.netty.buffer.ByteBufUtil;
 import io.netty.buffer.Unpooled;
 import java.util.ArrayList;
-import java.util.BitSet;
 import java.util.List;
 import java.util.Map.Entry;
 import org.opendaylight.protocol.bgp.linkstate.attribute.sr.SrNodeAttributesParser;
 import org.opendaylight.protocol.bgp.linkstate.spi.TlvUtil;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.ByteArray;
 import org.opendaylight.protocol.util.Ipv4Util;
 import org.opendaylight.protocol.util.Ipv6Util;
@@ -47,11 +47,13 @@ public final class NodeAttributesParser {
         throw new UnsupportedOperationException();
     }
 
+    private static final int FLAGS_SIZE = 8;
+
     // node flag bits
-    private static final int OVERLOAD_BIT = 7;
-    private static final int ATTACHED_BIT = 6;
-    private static final int EXTERNAL_BIT = 5;
-    private static final int ABBR_BIT = 4;
+    private static final int OVERLOAD_BIT = 0;
+    private static final int ATTACHED_BIT = 1;
+    private static final int EXTERNAL_BIT = 2;
+    private static final int ABBR_BIT = 3;
 
     /* Node Attribute TLVs */
     private static final int NODE_FLAG_BITS = 1024;
@@ -87,7 +89,7 @@ public final class NodeAttributesParser {
                 }
                 break;
             case NODE_FLAG_BITS:
-                final BitSet flags = BitSet.valueOf(ByteArray.readAllBytes(value));
+                final BitArray flags = BitArray.valueOf(value, FLAGS_SIZE);
                 builder.setNodeFlags(new NodeFlagBits(flags.get(OVERLOAD_BIT), flags.get(ATTACHED_BIT), flags.get(EXTERNAL_BIT), flags.get(ABBR_BIT)));
                 LOG.debug("Parsed Overload bit: {}, attached bit: {}, external bit: {}, area border router: {}.",
                     flags.get(OVERLOAD_BIT), flags.get(ATTACHED_BIT), flags.get(EXTERNAL_BIT), flags.get(ABBR_BIT));
@@ -189,20 +191,12 @@ public final class NodeAttributesParser {
     private static void serializeNodeFlagBits(final NodeFlagBits nodeFlagBits, final ByteBuf byteAggregator) {
         if (nodeFlagBits != null) {
             final ByteBuf nodeFlagBuf = Unpooled.buffer(1);
-            final BitSet flags = new BitSet(Byte.SIZE);
-            if (nodeFlagBits.isOverload() != null) {
-                flags.set(OVERLOAD_BIT, nodeFlagBits.isOverload());
-            }
-            if (nodeFlagBits.isAttached() != null) {
-                flags.set(ATTACHED_BIT, nodeFlagBits.isAttached());
-            }
-            if (nodeFlagBits.isExternal() != null) {
-                flags.set(EXTERNAL_BIT, nodeFlagBits.isExternal());
-            }
-            if (nodeFlagBits.isAbr() != null) {
-                flags.set(ABBR_BIT, nodeFlagBits.isAbr());
-            }
-            nodeFlagBuf.writeBytes(flags.toByteArray());
+            final BitArray flags = new BitArray(FLAGS_SIZE);
+            flags.set(OVERLOAD_BIT, nodeFlagBits.isOverload());
+            flags.set(ATTACHED_BIT, nodeFlagBits.isAttached());
+            flags.set(EXTERNAL_BIT, nodeFlagBits.isExternal());
+            flags.set(ABBR_BIT, nodeFlagBits.isAbr());
+            flags.toByteBuf(nodeFlagBuf);
             TlvUtil.writeTLV(NODE_FLAG_BITS, nodeFlagBuf, byteAggregator);
         }
     }
index 34045a441e9644cbd7a5809d3a9bebcedabd2c02..2297c9483a544debadc9d464cc491039ef113a50 100644 (file)
@@ -13,11 +13,11 @@ import io.netty.buffer.ByteBuf;
 import io.netty.buffer.ByteBufUtil;
 import io.netty.buffer.Unpooled;
 import java.util.ArrayList;
-import java.util.BitSet;
 import java.util.List;
 import java.util.Map.Entry;
 import org.opendaylight.protocol.bgp.linkstate.attribute.sr.SrPrefixAttributesParser;
 import org.opendaylight.protocol.bgp.linkstate.spi.TlvUtil;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.ByteArray;
 import org.opendaylight.protocol.util.Ipv4Util;
 import org.opendaylight.protocol.util.Ipv6Util;
@@ -47,7 +47,9 @@ public final class PrefixAttributesParser {
 
     private static final int ROUTE_TAG_LENGTH = 4;
     private static final int EXTENDED_ROUTE_TAG_LENGTH = 8;
-    private static final int UP_DOWN_BIT = 7;
+
+    private static final int FLAGS_SIZE = 8;
+    private static final int UP_DOWN_BIT = 0;
 
     /* Prefix Attribute TLVs */
     private static final int IGP_FLAGS = 1152;
@@ -76,7 +78,7 @@ public final class PrefixAttributesParser {
             LOG.trace("Prefix attribute TLV {}", key);
             switch (key) {
             case IGP_FLAGS:
-                final BitSet flags = BitSet.valueOf(ByteArray.readAllBytes(value));
+                final BitArray flags = BitArray.valueOf(value, FLAGS_SIZE);
                 final boolean upDownBit = flags.get(UP_DOWN_BIT);
                 builder.setIgpBits(new IgpBitsBuilder().setUpDown(new UpDown(upDownBit)).build());
                 LOG.debug("Parsed IGP flag (up/down bit) : {}", upDownBit);
@@ -141,12 +143,9 @@ public final class PrefixAttributesParser {
     static void serializePrefixAttributes(final PrefixAttributesCase prefixAttributesCase, final ByteBuf byteAggregator) {
         final PrefixAttributes prefixAtrributes = prefixAttributesCase.getPrefixAttributes();
         if (prefixAtrributes.getIgpBits() != null) {
-            final BitSet igpBit = new BitSet();
-            final Boolean bit = prefixAtrributes.getIgpBits().getUpDown().isUpDown();
-            if (bit != null) {
-                igpBit.set(UP_DOWN_BIT, bit);
-            }
-            TlvUtil.writeTLV(IGP_FLAGS, Unpooled.wrappedBuffer(igpBit.toByteArray()), byteAggregator);
+            final BitArray igpBit = new BitArray(FLAGS_SIZE);
+            igpBit.set(UP_DOWN_BIT, prefixAtrributes.getIgpBits().getUpDown().isUpDown());
+            TlvUtil.writeTLV(IGP_FLAGS, Unpooled.wrappedBuffer(igpBit.array()), byteAggregator);
         }
         if (prefixAtrributes.getRouteTags() != null) {
             final ByteBuf routeTagsBuf = Unpooled.buffer();
index 5b010432b31b2e4822d99c2618d66d48f1f344b5..18845e5d4ba8ad9c1152c3cc551280353954dc70 100644 (file)
@@ -9,7 +9,7 @@ package org.opendaylight.protocol.bgp.linkstate.attribute.sr;
 
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.ByteArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.link.state.SrAdjId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.link.state.SrAdjIdBuilder;
@@ -25,12 +25,12 @@ public final class SrLinkAttributesParser {
     private static final int ISO_SYSTEM_ID_SIZE = 6;
 
     /* Adj-SID flags */
-    private static final int ADDRESS_FAMILY_FLAG = 7;
-    private static final int BACKUP_FLAG = 6;
-    private static final int VALUE_FLAG = 5;
-    private static final int LOCAL_FLAG = 4;
-    private static final int SET_FLAG = 3;
-    private static final int FLAGS_SIZE = 1;
+    private static final int ADDRESS_FAMILY_FLAG = 0;
+    private static final int BACKUP_FLAG = 1;
+    private static final int VALUE_FLAG = 2;
+    private static final int LOCAL_FLAG = 3;
+    private static final int SET_FLAG = 4;
+    private static final int FLAGS_SIZE = 8;
 
     private SrLinkAttributesParser() {
         throw new UnsupportedOperationException();
@@ -41,7 +41,7 @@ public final class SrLinkAttributesParser {
             return new SrAdjIdBuilder().build();
         }
         final SrAdjIdBuilder srAdjIdBuilder = new SrAdjIdBuilder();
-        final BitSet flags = BitSet.valueOf(ByteArray.readBytes(buffer, FLAGS_SIZE));
+        final BitArray flags = BitArray.valueOf(buffer, FLAGS_SIZE);
         srAdjIdBuilder.setFlags(new AdjacencyFlags(flags.get(ADDRESS_FAMILY_FLAG), flags.get(BACKUP_FLAG), flags.get(LOCAL_FLAG), flags.get(SET_FLAG), flags.get(VALUE_FLAG)));
         srAdjIdBuilder.setWeight(new Weight(buffer.readUnsignedByte()));
         srAdjIdBuilder.setSid(new SidLabel(ByteArray.readAllBytes(buffer)));
@@ -51,23 +51,13 @@ public final class SrLinkAttributesParser {
     public static ByteBuf serializeAdjacencySegmentIdentifier(final SrAdjId srAdjId) {
         final ByteBuf value = Unpooled.buffer();
         final AdjacencyFlags srAdjIdFlags = srAdjId.getFlags();
-        final BitSet flags = new BitSet(FLAGS_SIZE);
-        if (srAdjIdFlags.isAddressFamily() != null) {
-            flags.set(ADDRESS_FAMILY_FLAG, srAdjIdFlags.isAddressFamily());
-        }
-        if (srAdjIdFlags.isBackup() != null) {
-            flags.set(BACKUP_FLAG, srAdjIdFlags.isBackup());
-        }
-        if (srAdjIdFlags.isValue() != null) {
-            flags.set(VALUE_FLAG, srAdjIdFlags.isValue());
-        }
-        if (srAdjIdFlags.isLocal() != null) {
-            flags.set(LOCAL_FLAG, srAdjIdFlags.isLocal());
-        }
-        if (srAdjIdFlags.isSetFlag() != null) {
-            flags.set(SET_FLAG, srAdjIdFlags.isSetFlag());
-        }
-        value.writeBytes(flags.toByteArray());
+        final BitArray flags = new BitArray(FLAGS_SIZE);
+        flags.set(ADDRESS_FAMILY_FLAG, srAdjIdFlags.isAddressFamily());
+        flags.set(BACKUP_FLAG, srAdjIdFlags.isBackup());
+        flags.set(VALUE_FLAG, srAdjIdFlags.isValue());
+        flags.set(LOCAL_FLAG, srAdjIdFlags.isLocal());
+        flags.set(SET_FLAG, srAdjIdFlags.isSetFlag());
+        flags.toByteBuf(value);
         value.writeByte(srAdjId.getWeight().getValue());
         value.writeBytes(srAdjId.getSid().getValue());
         return value;
@@ -78,7 +68,7 @@ public final class SrLinkAttributesParser {
             return new SrLanAdjIdBuilder().build();
         }
         final SrLanAdjIdBuilder srLanAdjIdBuilder = new SrLanAdjIdBuilder();
-        final BitSet flags = BitSet.valueOf(ByteArray.readBytes(buffer, FLAGS_SIZE));
+        final BitArray flags = BitArray.valueOf(buffer, FLAGS_SIZE);
         srLanAdjIdBuilder.setFlags(new AdjacencyFlags(flags.get(ADDRESS_FAMILY_FLAG), flags.get(BACKUP_FLAG), flags.get(LOCAL_FLAG), flags.get(SET_FLAG), flags.get(VALUE_FLAG)));
         srLanAdjIdBuilder.setWeight(new Weight(buffer.readUnsignedByte()));
         srLanAdjIdBuilder.setIsoSystemId(new IsoSystemIdentifier(ByteArray.readBytes(buffer, ISO_SYSTEM_ID_SIZE)));
@@ -89,23 +79,13 @@ public final class SrLinkAttributesParser {
     public static ByteBuf serializeLanAdjacencySegmentIdentifier(final SrLanAdjId srLanAdjId) {
         final ByteBuf value = Unpooled.buffer();
         final AdjacencyFlags srAdjIdFlags = srLanAdjId.getFlags();
-        final BitSet flags = new BitSet(FLAGS_SIZE);
-        if (srAdjIdFlags.isAddressFamily() != null) {
-            flags.set(ADDRESS_FAMILY_FLAG, srAdjIdFlags.isAddressFamily());
-        }
-        if (srAdjIdFlags.isBackup() != null) {
-            flags.set(BACKUP_FLAG, srAdjIdFlags.isBackup());
-        }
-        if (srAdjIdFlags.isValue() != null) {
-            flags.set(VALUE_FLAG, srAdjIdFlags.isValue());
-        }
-        if (srAdjIdFlags.isLocal() != null) {
-            flags.set(LOCAL_FLAG, srAdjIdFlags.isLocal());
-        }
-        if (srAdjIdFlags.isSetFlag() != null) {
-            flags.set(SET_FLAG, srAdjIdFlags.isSetFlag());
-        }
-        value.writeBytes(flags.toByteArray());
+        final BitArray flags = new BitArray(FLAGS_SIZE);
+        flags.set(ADDRESS_FAMILY_FLAG, srAdjIdFlags.isAddressFamily());
+        flags.set(BACKUP_FLAG, srAdjIdFlags.isBackup());
+        flags.set(VALUE_FLAG, srAdjIdFlags.isValue());
+        flags.set(LOCAL_FLAG, srAdjIdFlags.isLocal());
+        flags.set(SET_FLAG, srAdjIdFlags.isSetFlag());
+        flags.toByteBuf(value);
         value.writeByte(srLanAdjId.getWeight().getValue());
         value.writeBytes(srLanAdjId.getIsoSystemId().getValue());
         value.writeBytes(srLanAdjId.getSid().getValue());
index d776aaadf90ee5456249628ff05141b1473e77ee..f9da528897931c4516273734db03d64a4bd270f1 100644 (file)
@@ -10,9 +10,9 @@ package org.opendaylight.protocol.bgp.linkstate.attribute.sr;
 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.linkstate.spi.TlvUtil;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.ByteArray;
 import org.opendaylight.protocol.util.ByteBufWriteUtil;
 import org.opendaylight.protocol.util.Ipv4Util;
@@ -61,15 +61,15 @@ public final class SrNodeAttributesParser {
         throw new UnsupportedOperationException();
     }
 
-    private static final int FLAGS_SIZE = 1;
+    private static final int FLAGS_SIZE = 8;
 
     /* SR Capabilities flags */
-    private static final int IPV4 = 7;
-    private static final int IPV6 = 6;
+    private static final int IPV4 = 0;
+    private static final int IPV6 = 1;
 
     /* SID Label flags */
-    private static final int AFI = 7;
-    private static final int MIRROR = 6;
+    private static final int AFI = 0;
+    private static final int MIRROR = 1;
 
     /* SID Label Tlv types */
     private static final int SID_TLV_TYPE = 1;
@@ -150,7 +150,7 @@ public final class SrNodeAttributesParser {
 
     public static SrSidLabel parseSidLabelBinding(final ByteBuf buffer) {
         final SrSidLabelBuilder builder = new SrSidLabelBuilder();
-        final BitSet flags = BitSet.valueOf(ByteArray.readBytes(buffer, FLAGS_SIZE));
+        final BitArray flags = BitArray.valueOf(buffer, FLAGS_SIZE);
         builder.setSidLabelFlags(new SidLabelFlags(flags.get(AFI), flags.get(MIRROR)));
         builder.setWeight(new Weight(buffer.readUnsignedByte()));
         builder.setValueRange(buffer.readUnsignedShort());
@@ -223,14 +223,10 @@ public final class SrNodeAttributesParser {
 
     public static void serializeSidLabelBinding(final SrSidLabel binding, final ByteBuf buffer) {
         final SidLabelFlags flags = binding.getSidLabelFlags();
-        final BitSet bs = new BitSet(FLAGS_SIZE);
-        if (flags.isAddressFamily() != null) {
-            bs.set(AFI, flags.isAddressFamily());
-        }
-        if (flags.isMirrorContext() != null) {
-            bs.set(MIRROR, flags.isMirrorContext());
-        }
-        buffer.writeBytes(bs.toByteArray());
+        final BitArray bs = new BitArray(FLAGS_SIZE);
+        bs.set(AFI, flags.isAddressFamily());
+        bs.set(MIRROR, flags.isMirrorContext());
+        bs.toByteBuf(buffer);
         buffer.writeByte(binding.getWeight().getValue());
         buffer.writeShort(binding.getValueRange());
         final IpPrefix prefix = binding.getFecPrefix();
@@ -246,7 +242,7 @@ public final class SrNodeAttributesParser {
 
     public static SrCapabilities parseSrCapabilities(final ByteBuf buffer) {
         final SrCapabilitiesBuilder builder = new SrCapabilitiesBuilder();
-        final BitSet flags = BitSet.valueOf(ByteArray.readBytes(buffer, FLAGS_SIZE));
+        final BitArray flags = BitArray.valueOf(buffer, FLAGS_SIZE);
         builder.setFlags(new Flags(flags.get(IPV4), flags.get(IPV6)));
         builder.setValueRange((long)buffer.readUnsignedMedium());
         buffer.skipBytes(2);
@@ -256,14 +252,10 @@ public final class SrNodeAttributesParser {
 
     public static void serializeSrCapabilities(final SrCapabilities caps, final ByteBuf buffer) {
         final Flags flags = caps.getFlags();
-        final BitSet bs = new BitSet(FLAGS_SIZE);
-        if (flags.isIpv4() != null) {
-            bs.set(IPV4, flags.isIpv4());
-        }
-        if (flags.isIpv6() != null) {
-            bs.set(IPV6, flags.isIpv6());
-        }
-        buffer.writeBytes(bs.toByteArray());
+        final BitArray bs = new BitArray(FLAGS_SIZE);
+        bs.set(IPV4, flags.isIpv4());
+        bs.set(IPV6, flags.isIpv6());
+        bs.toByteBuf(buffer);
         buffer.writeMedium(caps.getValueRange().intValue());
         buffer.writeByte(SID_TLV_TYPE);
         final byte[] sid = caps.getSid().getValue();
index 1614cc129b14ae0a970b509bbd67cadca3ec6b8d..a28db5df0d218a073dd04623902483624224e8b0 100644 (file)
@@ -8,7 +8,7 @@
 package org.opendaylight.protocol.bgp.linkstate.attribute.sr;
 
 import io.netty.buffer.ByteBuf;
-import java.util.BitSet;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.ByteArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.prefix.state.SrPrefix;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev150210.prefix.state.SrPrefixBuilder;
@@ -18,22 +18,22 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segm
 
 public final class SrPrefixAttributesParser {
 
-    private static final int FLAGS_SIZE = 1;
+    private static final int FLAGS_SIZE = 8;
 
     private SrPrefixAttributesParser() {
         throw new UnsupportedOperationException();
     }
 
     /* Flags */
-    private static final int RE_ADVERTISEMENT = 7;
-    private static final int NODE_SID = 6;
-    private static final int NO_PHP = 5;
-    private static final int EXPLICIT_NULL = 4;
-    private static final int VALUE = 3;
-    private static final int LOCAL = 2;
+    private static final int RE_ADVERTISEMENT = 0;
+    private static final int NODE_SID = 1;
+    private static final int NO_PHP = 2;
+    private static final int EXPLICIT_NULL = 3;
+    private static final int VALUE = 4;
+    private static final int LOCAL = 5;
 
     public static SrPrefix parseSrPrefix(final ByteBuf buffer) {
-        final BitSet flags = BitSet.valueOf(ByteArray.readBytes(buffer, FLAGS_SIZE));
+        final BitArray flags = BitArray.valueOf(buffer, FLAGS_SIZE);
         final SrPrefixBuilder builder = new SrPrefixBuilder();
         builder.setFlags(new Flags(flags.get(EXPLICIT_NULL), flags.get(LOCAL), flags.get(NO_PHP), flags.get(NODE_SID), flags.get(RE_ADVERTISEMENT), flags.get(VALUE)));
         builder.setAlgorithm(Algorithm.forValue(buffer.readUnsignedByte()));
@@ -43,26 +43,14 @@ public final class SrPrefixAttributesParser {
 
     public static void serializeSrPrefix(final SrPrefix srPrefix, final ByteBuf buffer) {
         final Flags flags = srPrefix.getFlags();
-        final BitSet bs = new BitSet(FLAGS_SIZE);
-        if (flags.isReadvertisement() != null) {
-            bs.set(RE_ADVERTISEMENT, flags.isReadvertisement());
-        }
-        if (flags.isNodeSid() != null) {
-            bs.set(NODE_SID, flags.isNodeSid());
-        }
-        if (flags.isNoPhp() != null) {
-            bs.set(NO_PHP, flags.isNoPhp());
-        }
-        if (flags.isExplicitNull() != null) {
-            bs.set(EXPLICIT_NULL, flags.isExplicitNull());
-        }
-        if (flags.isValue() != null) {
-            bs.set(VALUE, flags.isValue());
-        }
-        if (flags.isLocal() != null) {
-            bs.set(LOCAL, flags.isLocal());
-        }
-        buffer.writeBytes(bs.toByteArray());
+        final BitArray bs = new BitArray(FLAGS_SIZE);
+        bs.set(RE_ADVERTISEMENT, flags.isReadvertisement());
+        bs.set(NODE_SID, flags.isNodeSid());
+        bs.set(NO_PHP, flags.isNoPhp());
+        bs.set(EXPLICIT_NULL, flags.isExplicitNull());
+        bs.set(VALUE, flags.isValue());
+        bs.set(LOCAL, flags.isLocal());
+        bs.toByteBuf(buffer);
         buffer.writeByte(srPrefix.getAlgorithm().getIntValue());
         buffer.writeBytes(srPrefix.getSid().getValue());
     }
index fbacf8d0ed9b0d368d71c30bbc7ba72bab862b5c..f8021e807a47ce8f2784cb0359a5639256d5c0d3 100644 (file)
@@ -36,8 +36,8 @@ public final class TlvUtil {
         byteAggregator.writeShort(type);
         byteAggregator.writeShort(value.writerIndex());
         byteAggregator.writeBytes(value);
-        value.readerIndex(0);
         if (LOG.isDebugEnabled()) {
+            value.readerIndex(0);
             LOG.debug("Serialized tlv type {} to: {}", type, ByteBufUtil.hexDump(value));
         }
     }
@@ -52,8 +52,8 @@ public final class TlvUtil {
         byteAggregator.writeByte(type);
         byteAggregator.writeByte(value.writerIndex());
         byteAggregator.writeBytes(value);
-        value.readerIndex(0);
         if (LOG.isDebugEnabled()) {
+            value.readerIndex(0);
             LOG.debug("Serialized tlv type {} to: {}", type, ByteBufUtil.hexDump(value));
         }
     }
index ad5304664568a95bcd870fd3e62c08a28e650e6f..f6c4c669cacdce0b920ec33e877be61341ae271d 100644 (file)
@@ -22,7 +22,7 @@ import org.opendaylight.protocol.bgp.parser.spi.AttributeRegistry;
 import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer;
 import org.opendaylight.protocol.concepts.AbstractRegistration;
 import org.opendaylight.protocol.concepts.HandlerRegistry;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.Values;
 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.message.rev130919.update.PathAttributesBuilder;
@@ -76,16 +76,16 @@ final class SimpleAttributeRegistry implements AttributeRegistry {
     }
 
     private void addAttribute(final ByteBuf buffer, final Map<Integer, RawAttribute> attributes) throws BGPDocumentedException {
-        final boolean[] flags = ByteArray.parseBits(buffer.readByte());
+        final BitArray flags = BitArray.valueOf(buffer.readByte());
         final int type = buffer.readUnsignedByte();
-        final int len = (flags[EXTENDED_LENGTH_BIT]) ? buffer.readUnsignedShort() : buffer.readUnsignedByte();
+        final int len = (flags.get(EXTENDED_LENGTH_BIT)) ? buffer.readUnsignedShort() : buffer.readUnsignedByte();
         if (!attributes.containsKey(type)) {
             final AttributeParser parser = this.handlers.getParser(type);
             if (parser == null) {
-                if (!flags[OPTIONAL_BIT]) {
+                if (!flags.get(OPTIONAL_BIT)) {
                     throw new BGPDocumentedException("Well known attribute not recognized.", BGPError.WELL_KNOWN_ATTR_NOT_RECOGNIZED);
                 }
-                if (flags[TRANSITIVE_BIT]) {
+                if (flags.get(TRANSITIVE_BIT)) {
                     // FIXME: transitive attributes need to be preserved
                     LOG.warn("Losing unrecognized transitive attribute {}. Some data might be missing from the output.", type);
                 } else {
index b127ff58e9a94f973ff764335291548d13726eb8..b4d0fd910d63b539266400d9ec6949e9ffa63dd6 100644 (file)
@@ -35,6 +35,23 @@ module bgp-rib {
         type inet:uri;
     }
 
+    typedef peer-id {
+        description
+            "An abstract peer identifier. The protocol part identifies
+            the type of the peer. One well-known protocol is define, which
+            has the following format: bgp://1.2.3.4, where 1.2.3.4 is the
+            peer's BGP Identifier in IPv4 dotted-quad format.";
+        type inet:uri;
+    }
+
+    typedef peer-role {
+        type enumeration {
+            enum ebgp;
+            enum ibgp;
+            enum rr-client;
+        }
+    }
+
     grouping route {
         container attributes {
             uses bgp-msg:path-attributes;
@@ -106,8 +123,22 @@ module bgp-rib {
             }
             key id;
 
-            list peers {
+            list peer {
+                key peer-id;
+                leaf peer-id {
+                    type peer-id;
+                }
+                leaf peer-role {
+                    type peer-role;
+                    mandatory true;
+                }
+
                 container adj-rib-in {
+                    description "Routes as we have received them from the peer.";
+                    uses rib;
+                }
+                container effective-rib-in {
+                    description "Routes as processed by inbound policy.";
                     uses rib;
                 }
                 container adj-rib-out {
index cca459b28a0a3550330bd6cadbbf339bf76a9684..558e9fa32099112afd05ed1242f5607154bcbd6b 100644 (file)
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>yang-binding</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>concepts</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>yang-common</artifactId>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
-            <artifactId>concepts</artifactId>
+            <artifactId>yang-data-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-model-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-data-impl</artifactId>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools.model</groupId>
             <artifactId>binding-generator-impl</artifactId>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>org.opendaylight.yangtools</groupId>
-            <artifactId>yang-model-api</artifactId>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>yang-parser-api</artifactId>
             <artifactId>yang-parser-impl</artifactId>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>org.opendaylight.yangtools</groupId>
-            <artifactId>yang-data-impl</artifactId>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AbstractExportPolicy.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AbstractExportPolicy.java
new file mode 100644 (file)
index 0000000..a6402b1
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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.rib.impl;
+
+import com.google.common.collect.Maps;
+import java.util.EnumMap;
+import java.util.Map;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+
+/**
+ * Defines the internal hooks invoked when a new route appears.
+ */
+abstract class AbstractExportPolicy {
+    // Invoked on routes which we send outside of our home AS
+    private static final class ToExternalExportPolicy extends AbstractExportPolicy {
+        @Override
+        ContainerNode effectiveAttributes(final PeerRole sourceRole, final ContainerNode attributes) {
+            // FIXME: filter all non-transitive attributes
+            // FIXME: but that may end up hurting our informedness
+            // FIXME: prepend local AS to add our AS into AS_PATH
+
+            switch (sourceRole) {
+            case Ebgp:
+                // eBGP -> eBGP, propagate
+                return attributes;
+            case Ibgp:
+                // Non-Client iBGP -> eBGP, propagate
+                return attributes;
+            case RrClient:
+                // Client iBGP -> eBGP, propagate
+                return attributes;
+            }
+            return attributes;
+        }
+    }
+
+    // Invoked on routes which we send to our normal home AS peers.
+    private static class ToInternalExportPolicy extends AbstractExportPolicy {
+        protected static ContainerNode prependClusterId(final ContainerNode attributes) {
+            // FIXME: prepend local CLUSTER_ID to CLUSTER_LIST
+            return attributes;
+        }
+
+        // Attributes when reflecting a route
+        protected static ContainerNode toClientAttributes(final ContainerNode attributes) {
+            // TODO: (defensiveness) verify ORIGINATOR_ID (should have been set)
+
+            return prependClusterId(attributes);
+        }
+
+        @Override
+        ContainerNode effectiveAttributes(final PeerRole sourceRole, final ContainerNode attributes) {
+            // Implement filtering according to <a ref="http://tools.ietf.org/html/rfc4456#section-8"/>.
+
+            switch (sourceRole) {
+            case Ebgp:
+                // eBGP -> Non-Client iBGP, propagate
+                return attributes;
+
+            case Ibgp:
+                // Non-Client iBGP -> Non-Client iBGP, block
+                return null;
+
+            case RrClient:
+                // Client iBGP -> Non-Client iBGP, reflect
+                return toClientAttributes(attributes);
+            }
+            return attributes;
+        }
+    }
+
+    /**
+     * Invoked on routes which we send to our reflector peers. This is a special-case of
+     * FromInternalImportPolicy.
+     */
+    private static final class ToReflectorClientExportPolicy extends AbstractExportPolicy {
+        @Override
+        ContainerNode effectiveAttributes(final PeerRole sourceRole, final ContainerNode attributes) {
+            switch (sourceRole) {
+            case Ebgp:
+                // eBGP -> Client iBGP, propagate
+                return attributes;
+            case Ibgp:
+                // Non-Client iBGP -> Client iBGP, reflect
+                // FIXME: add ORIGINATOR_ID
+
+                return ToInternalExportPolicy.prependClusterId(attributes);
+            case RrClient:
+                // Client iBGP -> Client iBGP, reflect
+                return ToInternalExportPolicy.toClientAttributes(attributes);
+            }
+
+            throw new IllegalStateException("Unhandled source role " + sourceRole);
+        }
+    }
+
+    static final Map<PeerRole, AbstractExportPolicy> POLICIES;
+
+    static {
+        final Map<PeerRole, AbstractExportPolicy> p = new EnumMap<PeerRole, AbstractExportPolicy>(PeerRole.class);
+        p.put(PeerRole.Ebgp, new ToExternalExportPolicy());
+        p.put(PeerRole.Ibgp, new ToInternalExportPolicy());
+        p.put(PeerRole.RrClient, new ToReflectorClientExportPolicy());
+        POLICIES = Maps.immutableEnumMap(p);
+    }
+
+    static AbstractExportPolicy forRole(final PeerRole peerRole) {
+        return POLICIES.get(peerRole);
+    }
+
+    /**
+     * Transform outgoing attributes according to policy.
+     *
+     * @param sourceRole role of the peer which originated the routes
+     * @param attributes outgoing attributes
+     * @return Filtered attributes, or null if the advertisement should be ignored.
+     */
+    abstract ContainerNode effectiveAttributes(PeerRole sourceRole, ContainerNode attributes);
+}
\ No newline at end of file
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AbstractIPRIBSupport.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AbstractIPRIBSupport.java
new file mode 100644 (file)
index 0000000..70c23a3
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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.rib.impl;
+
+import com.google.common.base.Optional;
+import java.util.Collection;
+import java.util.Collections;
+import org.opendaylight.controller.config.yang.bgp.rib.spi.AbstractRIBSupport;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Routes;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Common {@link org.opendaylight.protocol.bgp.rib.spi.RIBSupport} class for IPv4 and IPv6 addresses.
+ */
+abstract class AbstractIPRIBSupport extends AbstractRIBSupport {
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractIPRIBSupport.class);
+    private static final NodeIdentifier ROUTES = new NodeIdentifier(Routes.QNAME);
+
+    protected AbstractIPRIBSupport() {
+
+    }
+
+    protected abstract NodeIdentifier routeIdentifier();
+    protected abstract NodeIdentifier routesIdentifier();
+
+    @Override
+    public final Collection<Class<? extends DataObject>> cacheableAttributeObjects() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public final Collection<Class<? extends DataObject>> cacheableNlriObjects() {
+        return Collections.emptySet();
+    }
+
+    private static enum ApplyRoute {
+        DELETE() {
+            @Override
+            void apply(final DOMDataWriteTransaction tx, final YangInstanceIdentifier base, final MapEntryNode route, final ContainerNode attributes) {
+                // FIXME: we need convert the namespace here, as per the comment below
+                tx.delete(LogicalDatastoreType.OPERATIONAL, base.node(route.getIdentifier()));
+            }
+        },
+        PUT() {
+            @Override
+            void apply(final DOMDataWriteTransaction tx, final YangInstanceIdentifier base, final MapEntryNode route, final ContainerNode attributes) {
+                /*
+                 * FIXME: We have a problem with namespaces, as the namespace defining the content
+                 *        in the message and the namespace defining the content in rib differ.
+                 *        Moving ipv4/ipv6 routes out into a separate model would solve the problem,
+                 *        but that's going to break our REST compatibility. Is there a generic
+                 *        solution to this problem?
+                 *
+                 *        Even if there is not, we need to transition to that separate model, so
+                 *        we get uniform and fast translation.
+                 */
+                // FIXME: use attributes
+                tx.put(LogicalDatastoreType.OPERATIONAL, base.node(route.getIdentifier()), route);
+            }
+        };
+
+        abstract void apply(DOMDataWriteTransaction tx, YangInstanceIdentifier base, MapEntryNode route, final ContainerNode attributes);
+    }
+
+    private final void processDestination(final DOMDataWriteTransaction tx, final YangInstanceIdentifier tableId,
+            final ContainerNode destination, final ContainerNode attributes, final ApplyRoute function) {
+        if (destination != null) {
+            final Optional<DataContainerChild<? extends PathArgument, ?>> maybeRoutes = destination.getChild(routeIdentifier());
+            if (maybeRoutes.isPresent()) {
+                final DataContainerChild<? extends PathArgument, ?> routes = maybeRoutes.get();
+                if (routes instanceof MapNode) {
+                    final YangInstanceIdentifier base = tableId.node(ROUTES).node(routesIdentifier());
+                    for (MapEntryNode e : ((MapNode)routes).getValue()) {
+                        function.apply(tx, base, e, attributes);
+                    }
+                } else {
+                    LOG.warn("Routes {} are not a map", routes);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void putDestinationRoutes(final DOMDataWriteTransaction tx, final YangInstanceIdentifier tableId, final ContainerNode destination, final ContainerNode attributes) {
+        processDestination(tx, tableId, destination, attributes, ApplyRoute.PUT);
+    }
+
+    @Override
+    protected void deleteDestinationRoutes(final DOMDataWriteTransaction tx, final YangInstanceIdentifier tableId, final ContainerNode destination) {
+        processDestination(tx, tableId, destination, null, ApplyRoute.DELETE);
+    }
+}
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AbstractImportPolicy.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AbstractImportPolicy.java
new file mode 100644 (file)
index 0000000..d917450
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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.rib.impl;
+
+import java.util.EnumMap;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+
+/**
+ * Defines the internal hooks invoked when a new route appears.
+ */
+abstract class AbstractImportPolicy {
+    // Invoked on routes which we get from outside of our home AS
+    private static final class FromExternalImportPolicy extends AbstractImportPolicy {
+        @Override
+        ContainerNode effectiveAttributes(final ContainerNode attributes) {
+            // FIXME: filter all non-transitive attributes
+            // FIXME: but that may end up hurting our informedness
+            return attributes;
+        }
+    }
+
+    // Invoked on routes which we get from our normal home AS peers.
+    private static class FromInternalImportPolicy extends AbstractImportPolicy {
+        @Override
+        ContainerNode effectiveAttributes(final ContainerNode attributes) {
+            // FIXME: Implement filtering according to <a href="http://tools.ietf.org/html/rfc4456#section-8"/>.
+            return attributes;
+        }
+    }
+
+    /**
+     * Invoked on routes which we get from our reflector peers. This is a special-case of
+     * FromInternalImportPolicy.
+     *
+     */
+    private static final class FromReflectorClientImportPolicy extends FromInternalImportPolicy {
+        // FIXME: override if necessary
+    }
+
+    private static final Map<PeerRole, AbstractImportPolicy> POLICIES;
+
+    static {
+        final Map<PeerRole, AbstractImportPolicy> p = new EnumMap<PeerRole, AbstractImportPolicy>(PeerRole.class);
+        p.put(PeerRole.Ebgp, new FromExternalImportPolicy());
+        p.put(PeerRole.Ibgp, new FromInternalImportPolicy());
+        p.put(PeerRole.RrClient, new FromReflectorClientImportPolicy());
+        POLICIES = p;
+    }
+
+    static AbstractImportPolicy forRole(final PeerRole peerRole) {
+        return POLICIES.get(peerRole);
+    }
+
+    /**
+     * Transform incoming attributes according to policy.
+     *
+     * @param attributes received attributes
+     * @return Filtered attributes, or null if the advertisement should be ignored.
+     */
+    abstract @Nullable ContainerNode effectiveAttributes(@Nullable ContainerNode attributes);
+}
\ No newline at end of file
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibInWriter.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibInWriter.java
new file mode 100644 (file)
index 0000000..b630e7b
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * 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.rib.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
+import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.PathAttributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlri;
+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.rib.rev130925.bgp.rib.rib.peer.AdjRibIn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Attributes;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Writer of Adjacency-RIB-In for a single peer. An instance of this object
+ * is attached to each {@link BGPPeer} and {@link ApplicationPeer}.
+ */
+@NotThreadSafe
+final class AdjRibInWriter {
+    private static final Logger LOG = LoggerFactory.getLogger(AdjRibInWriter.class);
+
+    // FIXME: is there a utility method to construct this?
+    private static final ContainerNode EMPTY_ADJRIBIN = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(AdjRibIn.QNAME)).addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build()).build();
+    private static final LeafNode<Boolean> ATTRIBUTES_UPTODATE_FALSE = ImmutableNodes.leafNode(QName.create(Attributes.QNAME, "uptodate"), Boolean.FALSE);
+    private static final LeafNode<Boolean> ATTRIBUTES_UPTODATE_TRUE = ImmutableNodes.leafNode(ATTRIBUTES_UPTODATE_FALSE.getNodeType(), Boolean.TRUE);
+    private static final QName AFI_QNAME = QName.create(Tables.QNAME, "afi");
+    private static final QName SAFI_QNAME = QName.create(Tables.QNAME, "safi");
+
+    private final Map<TablesKey, TableContext> tables;
+    private final YangInstanceIdentifier adjRibInRoot;
+    private final DOMTransactionChain chain;
+
+    /*
+     * FIXME: transaction chain has to be instantiated in caller, so it can terminate us when it fails.
+     */
+    private AdjRibInWriter(final DOMTransactionChain chain, final YangInstanceIdentifier adjRibInRoot, final Map<TablesKey, TableContext> tables) {
+        this.chain = Preconditions.checkNotNull(chain);
+        this.adjRibInRoot = Preconditions.checkNotNull(adjRibInRoot);
+        this.tables = Preconditions.checkNotNull(tables);
+    }
+
+    static AdjRibInWriter create(final DOMTransactionChain chain, final YangInstanceIdentifier peer) {
+        // Not used often, no need to optimize it via builder
+        final YangInstanceIdentifier adjRibInRoot = peer.node(EMPTY_ADJRIBIN.getIdentifier());
+
+        // Create top-level AdjRibIn with an empty table list
+        final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction();
+        tx.put(LogicalDatastoreType.OPERATIONAL, adjRibInRoot, EMPTY_ADJRIBIN);
+        tx.submit();
+
+        return new AdjRibInWriter(chain, adjRibInRoot, Collections.<TablesKey, TableContext>emptyMap());
+    }
+
+    /**
+     * Transform this writer to a new writer, which is in charge of specified tables.
+     * Empty tables are created for new entries and old tables are deleted. Once this
+     * method returns, the old instance must not be reasonably used.
+     *
+     * @param tableTypes New tables, must not be null
+     * @return New writer
+     */
+    AdjRibInWriter changeTableTypes(final RIBExtensionConsumerContext registry, final Set<TablesKey> tableTypes) {
+        if (tableTypes.equals(tables.keySet())) {
+            return this;
+        }
+
+        final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction();
+
+        // Wipe tables which are not present in the new types
+        for (Entry<TablesKey, TableContext> e : tables.entrySet()) {
+            if (!tableTypes.contains(e.getKey())) {
+                e.getValue().removeTable(tx);
+            }
+        }
+
+        final Builder<TablesKey, TableContext> tb = ImmutableMap.builder();
+        for (TablesKey k : tableTypes) {
+            TableContext ctx = tables.get(k);
+            if (ctx == null) {
+                final RIBSupport rs = registry.getRIBSupport(k);
+                if (rs == null) {
+                    LOG.warn("No support for table type {}, skipping it", k);
+                    continue;
+                }
+
+                // We will use table keys very often, make sure they are optimized
+                final InstanceIdentifierBuilder idb = YangInstanceIdentifier.builder(adjRibInRoot);
+
+                // FIXME: use codec to translate the key
+                final Map<QName, Object> keyValues = ImmutableMap.<QName, Object>of(AFI_QNAME, BindingReflections.getQName(k.getAfi()), SAFI_QNAME, BindingReflections.getQName(k.getSafi()));
+                final NodeIdentifierWithPredicates key = new NodeIdentifierWithPredicates(Tables.QNAME, keyValues);
+                idb.nodeWithKey(key.getNodeType(), keyValues);
+
+                ctx = new TableContext(rs, idb.build());
+                ctx.clearTable(tx);
+            } else {
+                tx.merge(LogicalDatastoreType.OPERATIONAL, ctx.getTableId().node(Attributes.QNAME).node(ATTRIBUTES_UPTODATE_FALSE.getNodeType()), ATTRIBUTES_UPTODATE_FALSE);
+            }
+
+            tb.put(k, ctx);
+        }
+
+        tx.submit();
+
+        return new AdjRibInWriter(chain, adjRibInRoot, tb.build());
+    }
+
+    /**
+     * Clean all routes in specified tables
+     *
+     * @param tableTypes Tables to clean.
+     */
+    void cleanTables(final Collection<TablesKey> tableTypes) {
+        final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction();
+
+        for (TablesKey k : tableTypes) {
+            LOG.debug("Clearing table {}", k);
+            tables.get(k).clearTable(tx);
+        }
+
+        tx.submit();
+    }
+
+    void markTablesUptodate(final Collection<TablesKey> tableTypes) {
+        final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction();
+
+        for (TablesKey k : tableTypes) {
+            final TableContext ctx = tables.get(k);
+            tx.merge(LogicalDatastoreType.OPERATIONAL, ctx.getTableId().node(Attributes.QNAME).node(ATTRIBUTES_UPTODATE_TRUE.getNodeType()), ATTRIBUTES_UPTODATE_TRUE);
+        }
+
+        tx.submit();
+    }
+
+    void updateRoutes(final MpReachNlri nlri, final PathAttributes attributes) {
+        final TablesKey key = new TablesKey(nlri.getAfi(), nlri.getSafi());
+        final TableContext ctx = tables.get(key);
+        if (ctx == null) {
+            LOG.debug("No table for {}, not accepting NLRI {}", key, nlri);
+            return;
+        }
+
+        final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction();
+        ctx.writeRoutes(null, tx, nlri, attributes);
+        tx.submit();
+    }
+
+    void removeRoutes(final MpUnreachNlri nlri) {
+        final TablesKey key = new TablesKey(nlri.getAfi(), nlri.getSafi());
+        final TableContext ctx = tables.get(key);
+        if (ctx == null) {
+            LOG.debug("No table for {}, not accepting NLRI {}", key, nlri);
+            return;
+        }
+
+        final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction();
+        ctx.removeRoutes(null, tx, nlri);
+        tx.submit();
+    }
+}
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibOutListener.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibOutListener.java
new file mode 100644 (file)
index 0000000..374633f
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.rib.impl;
+
+import com.google.common.base.Preconditions;
+import java.util.Collection;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
+import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.UpdateBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+
+/**
+ * Instantiated for each peer and table, listens on a particular peer's adj-rib-out,
+ * performs transcoding to BA form (message) and sends it down the channel.
+ */
+@NotThreadSafe
+final class AdjRibOutListener implements DOMDataTreeChangeListener {
+    private final ChannelOutputLimiter session;
+    private final RIBSupport ribSupport;
+
+    AdjRibOutListener(final RIBSupport ribSupport, final ChannelOutputLimiter session) {
+        this.ribSupport = Preconditions.checkNotNull(ribSupport);
+        this.session = Preconditions.checkNotNull(session);
+    }
+
+    @Override
+    public void onDataTreeChanged(final Collection<DataTreeCandidate> changes) {
+        for (DataTreeCandidate tc : changes) {
+            final UpdateBuilder ub = new UpdateBuilder();
+
+            // FIXME: fill the structure
+
+            session.write(ub.build());
+        }
+
+        session.flush();
+    }
+
+}
index 7720538b1c0ab8bb998b08cf2eef820f90a429f7..ba4e1a455240002b643c0f7062a011f78f100c9b 100644 (file)
@@ -107,6 +107,7 @@ public class BGPSessionImpl extends AbstractProtocolSession<Notification> implem
     private final AsNumber asNumber;
     private final Ipv4Address bgpId;
     private final BGPPeerRegistry peerRegistry;
+    private final ChannelOutputLimiter limiter;
 
     private BGPSessionStats sessionStats;
 
@@ -120,6 +121,7 @@ public class BGPSessionImpl extends AbstractProtocolSession<Notification> implem
             final BGPPeerRegistry peerRegitry) {
         this.listener = Preconditions.checkNotNull(listener);
         this.channel = Preconditions.checkNotNull(channel);
+        this.limiter = new ChannelOutputLimiter(this);
         this.holdTimerValue = (remoteOpen.getHoldTimer() < localHoldTimer) ? remoteOpen.getHoldTimer() : localHoldTimer;
         LOG.info("BGP HoldTimer new value: {}", this.holdTimerValue);
         this.keepAlive = this.holdTimerValue / KA_TO_DEADTIMER_RATIO;
@@ -171,7 +173,7 @@ public class BGPSessionImpl extends AbstractProtocolSession<Notification> implem
         LOG.info("Closing session: {}", this);
 
         if (this.state != State.IDLE) {
-            this.sendMessage(new NotifyBuilder().setErrorCode(BGPError.CEASE.getCode()).setErrorSubcode(
+            this.writeAndFlush(new NotifyBuilder().setErrorCode(BGPError.CEASE.getCode()).setErrorSubcode(
                     BGPError.CEASE.getSubcode()).build());
             removePeerSession();
             this.channel.close();
@@ -224,31 +226,44 @@ public class BGPSessionImpl extends AbstractProtocolSession<Notification> implem
         }
     }
 
-    synchronized void sendMessage(final Notification msg) {
-        try {
-            this.channel.writeAndFlush(msg).addListener(
-                new ChannelFutureListener() {
-                    @Override
-                    public void operationComplete(final ChannelFuture f) {
-                        if (!f.isSuccess()) {
-                            LOG.info("Failed to send message {} to socket {}", msg, f.cause(), BGPSessionImpl.this.channel);
-                        } else {
-                            LOG.trace("Message {} sent to socket {}", msg, BGPSessionImpl.this.channel);
-                        }
+    @GuardedBy("this")
+    private final void writeEpilogue(final ChannelFuture future, final Notification msg) {
+        future.addListener(
+            new ChannelFutureListener() {
+                @Override
+                public void operationComplete(final ChannelFuture f) {
+                    if (!f.isSuccess()) {
+                        LOG.info("Failed to send message {} to socket {}", msg, f.cause(), BGPSessionImpl.this.channel);
+                    } else {
+                        LOG.trace("Message {} sent to socket {}", msg, BGPSessionImpl.this.channel);
                     }
-                });
-            this.lastMessageSentAt = System.nanoTime();
-            this.sessionStats.updateSentMsgTotal();
-            if (msg instanceof Update) {
-                this.sessionStats.updateSentMsgUpd();
-            } else if (msg instanceof Notify) {
-                this.sessionStats.updateSentMsgErr((Notify) msg);
-            }
+                }
+            });
+        this.lastMessageSentAt = System.nanoTime();
+        this.sessionStats.updateSentMsgTotal();
+        if (msg instanceof Update) {
+            this.sessionStats.updateSentMsgUpd();
+        } else if (msg instanceof Notify) {
+            this.sessionStats.updateSentMsgErr((Notify) msg);
+        }
+    }
+
+    void flush() {
+        this.channel.flush();
+    }
+
+    synchronized void write(final Notification msg) {
+        try {
+            writeEpilogue(this.channel.write(msg), msg);
         } catch (final Exception e) {
             LOG.warn("Message {} was not sent.", msg, e);
         }
     }
 
+    synchronized void writeAndFlush(final Notification msg) {
+        writeEpilogue(this.channel.writeAndFlush(msg), msg);
+    }
+
     private synchronized void closeWithoutMessage() {
         LOG.debug("Closing session: {}", this);
         removePeerSession();
@@ -263,7 +278,7 @@ public class BGPSessionImpl extends AbstractProtocolSession<Notification> implem
      * @param closeObject
      */
     private void terminate(final BGPError error) {
-        this.sendMessage(new NotifyBuilder().setErrorCode(error.getCode()).setErrorSubcode(error.getSubcode()).build());
+        this.writeAndFlush(new NotifyBuilder().setErrorCode(error.getCode()).setErrorSubcode(error.getSubcode()).build());
         this.closeWithoutMessage();
 
         this.listener.onSessionTerminated(this, new BGPTerminationReason(error));
@@ -317,7 +332,7 @@ public class BGPSessionImpl extends AbstractProtocolSession<Notification> implem
         long nextKeepalive = this.lastMessageSentAt + TimeUnit.SECONDS.toNanos(this.keepAlive);
 
         if (ct >= nextKeepalive) {
-            this.sendMessage(KEEP_ALIVE);
+            this.writeAndFlush(KEEP_ALIVE);
             nextKeepalive = this.lastMessageSentAt + TimeUnit.SECONDS.toNanos(this.keepAlive);
             this.sessionStats.updateSentMsgKA();
         }
@@ -389,4 +404,8 @@ public class BGPSessionImpl extends AbstractProtocolSession<Notification> implem
     public synchronized void resetSessionStats() {
         this.sessionStats.resetStats();
     }
+
+    ChannelOutputLimiter getLimiter() {
+        return limiter;
+    }
 }
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BestPath.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BestPath.java
new file mode 100644 (file)
index 0000000..b9d0177
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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.rib.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.UnsignedInteger;
+import javax.annotation.Nonnull;
+
+final class BestPath {
+    private final UnsignedInteger routerId;
+    private final BestPathState state;
+
+    BestPath(@Nonnull final UnsignedInteger routerId, @Nonnull final BestPathState state) {
+        this.routerId = Preconditions.checkNotNull(routerId);
+        this.state = Preconditions.checkNotNull(state);
+    }
+
+    UnsignedInteger getRouterId() {
+        return routerId;
+    }
+
+    BestPathState getState() {
+        return state;
+    }
+}
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BestPathSelector.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BestPathSelector.java
new file mode 100644 (file)
index 0000000..09562a0
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * 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.rib.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.primitives.UnsignedInteger;
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.OriginatorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpOrigin;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+
+final class BestPathSelector {
+    private static final Collection<PathArgument> ORIGINATOR_ID = ImmutableList.<PathArgument>of(new NodeIdentifier(OriginatorId.QNAME), new NodeIdentifier(QName.create(OriginatorId.QNAME, "originator")));
+
+    private final Long ourAs;
+    private UnsignedInteger bestOriginatorId = null;
+    private UnsignedInteger bestRouterId = null;
+    private BestPathState bestState = null;
+
+    BestPathSelector(final Long ourAs) {
+        this.ourAs = Preconditions.checkNotNull(ourAs);
+    }
+
+    void processPath(final UnsignedInteger routerId, final ContainerNode attrs) {
+        Preconditions.checkNotNull(routerId, "Router ID may not be null");
+
+        // Consider only non-null attributes
+        if (attrs != null) {
+            /*
+             * RFC 4456 mandates the use of Originator IDs instead of Router ID for
+             * selection purposes.
+             */
+            final Optional<NormalizedNode<?, ?>> maybeOriginatorId = NormalizedNodes.findNode(attrs, ORIGINATOR_ID);
+            final UnsignedInteger originatorId;
+            if (maybeOriginatorId.isPresent()) {
+                originatorId = RouterIds.routerIdForAddress((String) ((LeafNode<?>)maybeOriginatorId.get()).getValue());
+            } else {
+                originatorId = routerId;
+            }
+
+            /*
+             * Store the new details if we have nothing stored or when the selection algorithm indicates new details
+             * are better.
+             */
+            final BestPathState state = new BestPathState(attrs);
+            if (this.bestOriginatorId == null || selectPath(originatorId, state)) {
+                this.bestOriginatorId = originatorId;
+                this.bestRouterId = routerId;
+                this.bestState = state;
+            }
+        }
+    }
+
+    BestPath result() {
+        return this.bestRouterId == null ? null : new BestPath(this.bestRouterId, this.bestState);
+    }
+
+    /**
+     * Chooses best route according to BGP best path selection.
+     *
+     * @param originatorId of the new route
+     * @param state attributes of the new route
+     * @return true if the existing path is better, false if the new path is better
+     */
+    private boolean selectPath(final @Nonnull UnsignedInteger originatorId, final @Nonnull BestPathState state) {
+        // 1. prefer path with accessible nexthop
+        // - we assume that all nexthops are accessible
+
+        /*
+         * 2. prefer path with higher LOCAL_PREF
+         *
+         * FIXME: for eBGP cases (when the LOCAL_PREF is missing), we should assign a policy-based preference
+         *        before we ever get here.
+         */
+        if (bestState.getLocalPref() == null && state.getLocalPref() != null) {
+            return true;
+        }
+        if (bestState.getLocalPref() != null && state.getLocalPref() == null) {
+            return false;
+        }
+        if (state.getLocalPref() != null) {
+            if (state.getLocalPref() > this.bestState.getLocalPref()) {
+                return true;
+            }
+        }
+
+        // 3. prefer learned path
+        // - we assume that all paths are learned
+
+        // 4. prefer the path with the shortest AS_PATH.
+        if (this.bestState.getAsPathLength() > state.getAsPathLength()) {
+            return true;
+        }
+
+        // 5. prefer the path with the lowest origin type
+        // - IGP is lower than Exterior Gateway Protocol (EGP), and EGP is lower than INCOMPLETE
+        if (!this.bestState.getOrigin().equals(state.getOrigin())) {
+            final BgpOrigin bo = this.bestState.getOrigin();
+            final BgpOrigin no = state.getOrigin();
+
+            // This trick relies on the order in which the values are declared in the model.
+            if (no.ordinal() < bo.ordinal()) {
+                return true;
+            }
+        }
+
+        // FIXME: we should be able to cache the best AS
+        final Long bestAs = this.bestState.getPeerAs();
+        final Long newAs = state.getPeerAs();
+
+        /*
+         * Checks 6 and 7 are mutually-exclusive, as MEDs are comparable
+         * only when the routes originated from the same AS. On the other
+         * hand, when they are from the same AS, they are in the same iBGP/eBGP
+         * relationship.
+         *
+         */
+        if (bestAs.equals(newAs)) {
+            // 6. prefer the path with the lowest multi-exit discriminator (MED)
+            if (this.bestState.getMultiExitDisc() != null || state.getMultiExitDisc() != null) {
+                final Long bmed = this.bestState.getMultiExitDisc();
+                final Long nmed = state.getMultiExitDisc();
+                if (nmed < bmed) {
+                    return true;
+                }
+            }
+        } else {
+            /*
+             * 7. prefer eBGP over iBGP paths
+             *
+             * EBGP is peering between two different AS, whereas IBGP is between same AS (Autonomous System),
+             * so we just compare the AS numbers to our AS.
+             *
+             * FIXME: we should know this information from the peer directly.
+             */
+            if (!this.ourAs.equals(bestAs) && this.ourAs.equals(newAs)) {
+                return true;
+            }
+        }
+
+        // 8. Prefer the path with the lowest IGP metric to the BGP next hop.
+        // - no next hop metric is advertised
+
+        /*
+         * 9. When both paths are external, prefer the path that was received first (the oldest one).
+         *
+         * FIXME: we do not want to store an explicit timer for each set due to performance/memory
+         *        constraints. Our caller has the information about which attributes have changed
+         *        since the selection process has ran last time, which may be a good enough approximation,
+         *        but its properties need to be analyzed.
+         */
+
+        /*
+         * 10. Prefer the route that comes from the BGP router with the lowest router ID.
+         *
+         * This is normally guaranteed by the iteration order of our caller, which runs selection
+         * in the order of increasing router ID, but RFC-4456 Route Reflection throws a wrench into that.
+         *
+         * With RFC-5004, this gets a bit easier, because it completely eliminates step f) and later :-)
+         *
+         * RFC-5004 states that this algorithm should end here and select existing path over new path in the
+         * best path selection process. Benefits are listed in the RFC: @see http://tools.ietf.org/html/rfc500
+         * - This algorithm SHOULD NOT be applied when either path is from a BGP Confederation peer.
+         *  - not applicable, we don't deal with confederation peers
+         * - The algorithm SHOULD NOT be applied when both paths are from peers with an identical BGP identifier
+         *   (i.e., there exist parallel BGP sessions between two BGP speakers).
+         *  - not applicable, BUG-2631 prevents parallel sessions to be created.
+         */
+        return true;
+    }
+}
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BestPathState.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BestPathState.java
new file mode 100644 (file)
index 0000000..eeecacc
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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.rib.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.AsPath;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.LocalPref;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.MultiExitDisc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Origin;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.as.path.Segments;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpOrigin;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.AListCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.ASetCase;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+
+@NotThreadSafe
+final class BestPathState {
+    private static final Collection<PathArgument> AS_PATH = ImmutableList.<PathArgument>of(new NodeIdentifier(AsPath.QNAME), new NodeIdentifier(Segments.QNAME));
+    private static final Collection<PathArgument> LOCAL_PREF = ImmutableList.<PathArgument>of(new NodeIdentifier(LocalPref.QNAME), new NodeIdentifier(QName.create(LocalPref.QNAME, "pref")));
+    private static final Collection<PathArgument> MED = ImmutableList.<PathArgument>of(new NodeIdentifier(MultiExitDisc.QNAME), new NodeIdentifier(QName.create(MultiExitDisc.QNAME, "med")));
+    private static final Collection<PathArgument> ORIGIN = ImmutableList.<PathArgument>of(new NodeIdentifier(Origin.QNAME), new NodeIdentifier(QName.create(Origin.QNAME, "value")));
+
+    private final ContainerNode attributes;
+    private Long localPref;
+    private Long multiExitDisc;
+    private BgpOrigin origin;
+    private final Long peerAs = 0L;
+    private final int asPathLength = 0;
+    private boolean resolved;
+
+    BestPathState(final ContainerNode attributes) {
+        this.attributes = Preconditions.checkNotNull(attributes);
+    }
+
+    private void resolveValues() {
+        if (resolved) {
+            return;
+        }
+
+        final Optional<NormalizedNode<?, ?>> maybeLocalPref = NormalizedNodes.findNode(attributes, LOCAL_PREF);
+        if (maybeLocalPref.isPresent()) {
+            localPref = (Long) ((LeafNode<?>)maybeLocalPref.get()).getValue();
+        } else {
+            localPref = null;
+        }
+
+        final Optional<NormalizedNode<?, ?>> maybeMultiExitDisc = NormalizedNodes.findNode(attributes, MED);
+        if (maybeMultiExitDisc.isPresent()) {
+            multiExitDisc = (Long) ((LeafNode<?>)maybeMultiExitDisc.get()).getValue();
+        } else {
+            multiExitDisc = null;
+        }
+
+        final Optional<NormalizedNode<?, ?>> maybeOrigin = NormalizedNodes.findNode(attributes, ORIGIN);
+        if (maybeOrigin.isPresent()) {
+            final String originStr = (String) ((LeafNode<?>)maybeOrigin.get()).getValue();
+            switch (originStr) {
+            case "igp":
+                origin = BgpOrigin.Igp;
+                break;
+            case "egp":
+                origin = BgpOrigin.Egp;
+                break;
+            case "incomplete":
+                origin = BgpOrigin.Incomplete;
+                break;
+            default:
+                throw new IllegalArgumentException("Unhandleed origin value " + originStr);
+            }
+        } else {
+            origin = null;
+        }
+
+        final Optional<NormalizedNode<?, ?>> maybeSegments = NormalizedNodes.findNode(attributes, AS_PATH);
+        if (maybeSegments.isPresent()) {
+            final UnkeyedListNode segments = (UnkeyedListNode) maybeSegments.get();
+
+            if (segments.getSize() != 0) {
+                // FIXME: peer AS number
+
+                // FIXME: asPathLength = countAsPath(this.bestState.getAsPath().getSegments());
+                boolean haveSegment;
+                for (UnkeyedListEntryNode s : segments.getValue()) {
+
+                }
+            }
+        }
+
+        resolved = true;
+    }
+
+    Long getLocalPref() {
+        resolveValues();
+        return localPref;
+    }
+
+    Long getMultiExitDisc() {
+        resolveValues();
+        return multiExitDisc;
+    }
+
+    BgpOrigin getOrigin() {
+        resolveValues();
+        return origin;
+    }
+
+    Long getPeerAs() {
+        resolveValues();
+        return peerAs;
+    }
+
+    int getAsPathLength() {
+        resolveValues();
+        return asPathLength;
+    }
+
+    private static int countAsPath(final List<Segments> segments) {
+        // an AS_SET counts as 1, no matter how many ASs are in the set.
+        int count = 0;
+        boolean setPresent = false;
+        for (final Segments s : segments) {
+            if (s.getCSegment() instanceof ASetCase) {
+                setPresent = true;
+            } else {
+                final AListCase list = (AListCase) s.getCSegment();
+                count += list.getAList().getAsSequence().size();
+            }
+        }
+        return (setPresent) ? count + 1 : count;
+    }
+
+    private static AsNumber getPeerAs(final List<Segments> segments) {
+        if (segments.isEmpty()) {
+            return null;
+        }
+
+        final AListCase first = (AListCase) segments.get(0).getCSegment();
+        return first.getAList().getAsSequence().get(0).getAs();
+    }
+
+}
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/ChannelOutputLimiter.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/ChannelOutputLimiter.java
new file mode 100644 (file)
index 0000000..3a610b6
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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.rib.impl;
+
+import com.google.common.base.Preconditions;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import javax.annotation.concurrent.ThreadSafe;
+import org.opendaylight.yangtools.yang.binding.Notification;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A best-effort output limiter. It does not provide any fairness, and acts as a blocking gate-keeper
+ * for a sessions' channel.
+ */
+@ThreadSafe
+final class ChannelOutputLimiter extends ChannelInboundHandlerAdapter {
+    private static final Logger LOG = LoggerFactory.getLogger(ChannelOutputLimiter.class);
+    private final BGPSessionImpl session;
+    private volatile boolean blocked;
+
+    ChannelOutputLimiter(final BGPSessionImpl session) {
+        this.session = Preconditions.checkNotNull(session);
+    }
+
+    private void ensureWritable() {
+        if (blocked) {
+            LOG.trace("Blocked slow path tripped on session {}", session);
+            synchronized (this) {
+                while (blocked) {
+                    try {
+                        LOG.debug("Waiting for session {} to become writable", session);
+                        this.wait();
+                    } catch (InterruptedException e) {
+                        throw new IllegalStateException("Interrupted while waiting for channel to come back", e);
+                    }
+                }
+
+                LOG.debug("Resuming write on session {}", session);
+            }
+        }
+    }
+
+    void write(final Notification msg) {
+        ensureWritable();
+        session.write(msg);
+    }
+
+    void writeAndFlush(final Notification msg) {
+        ensureWritable();
+        session.writeAndFlush(msg);
+    }
+
+    void flush() {
+        session.flush();
+    }
+
+    @Override
+    public void channelWritabilityChanged(final ChannelHandlerContext ctx) throws Exception {
+        final boolean w = ctx.channel().isWritable();
+
+        synchronized (this) {
+            blocked = !w;
+            LOG.debug("Writes on session {} {}", session, w ? "unblocked" : "blocked");
+
+            if (w) {
+                this.notifyAll();
+            }
+        }
+
+        super.channelWritabilityChanged(ctx);
+    }
+
+    @Override
+    public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
+        synchronized (this) {
+            blocked = false;
+            this.notifyAll();
+        }
+
+        super.channelInactive(ctx);
+    }
+}
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/EffectiveRibInWriter.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/EffectiveRibInWriter.java
new file mode 100644 (file)
index 0000000..45a3287
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * 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.rib.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
+import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of the BGP import policy. Listens on all Adj-RIB-In, inspects all inbound
+ * routes in the context of the advertising peer's role and applies the inbound policy.
+ *
+ * Inbound policy is applied as follows:
+ *
+ * 1) if the peer is an eBGP peer, perform attribute replacement and filtering
+ * 2) check if a route is admissible based on attributes attached to it, as well as the
+ *    advertising peer's role
+ * 3) output admitting routes with edited attributes into /bgp-rib/rib/peer/effective-rib-in/tables/routes
+ *
+ * Note that we maintain the peer roles using a DCL, even if we could look up our internal
+ * structures. This is done so we maintain causality and loose coupling.
+ */
+@NotThreadSafe
+final class EffectiveRibInWriter {
+    private static final Predicate<PathArgument> IS_PEER = new Predicate<PathArgument>() {
+        @Override
+        public boolean apply(final PathArgument input) {
+            return input.getNodeType().equals(Peer.QNAME);
+        }
+    };
+    private static final Predicate<PathArgument> IS_TABLES = new Predicate<PathArgument>() {
+        @Override
+        public boolean apply(final PathArgument input) {
+            return input.getNodeType().equals(Tables.QNAME);
+        }
+    };
+    private static final Logger LOG = LoggerFactory.getLogger(EffectiveRibInWriter.class);
+    private static final QName PEER_ID = QName.create(Peer.QNAME, "peer-id");
+
+    // FIXME: implement as id.firstIdentifierOf(IS_PEER), null indicating not found
+    private static final NodeIdentifierWithPredicates firstKeyOf(final YangInstanceIdentifier id, final Predicate<PathArgument> match) {
+        final PathArgument ret = Iterables.find(id.getPathArguments(), IS_PEER);
+        Preconditions.checkArgument(ret instanceof NodeIdentifierWithPredicates, "Non-key peer identifier %s", ret);
+        return (NodeIdentifierWithPredicates) ret;
+    }
+
+    static final NodeIdentifierWithPredicates peerKey(final YangInstanceIdentifier id) {
+        return firstKeyOf(id, IS_PEER);
+    }
+
+    static final PeerId peerId(final NodeIdentifierWithPredicates peerKey) {
+        return (PeerId) peerKey.getKeyValues().get(PEER_ID);
+    }
+
+    private static final NodeIdentifierWithPredicates tableKey(final YangInstanceIdentifier id) {
+        return firstKeyOf(id, IS_TABLES);
+    }
+
+    /**
+     * Maintains the mapping of PeerId -> Role inside. We are subscribed to our target leaf,
+     * but that is a wildcard:
+     *     /bgp-rib/rib/peer/peer-role
+     *
+     * MD-SAL assumption: we are getting one {@link DataTreeCandidate} for each expanded
+     *                    wildcard path, so are searching for a particular key.
+     */
+    private final class PeerRoleListener implements DOMDataTreeChangeListener {
+        @Override
+        public void onDataTreeChanged(final Collection<DataTreeCandidate> changes) {
+            synchronized (policies) {
+                for (DataTreeCandidate tc : changes) {
+                    // Obtain the peer's key
+                    final NodeIdentifierWithPredicates peerKey = peerKey(tc.getRootPath());
+
+                    // Check for removal
+                    final Optional<NormalizedNode<?, ?>> maybePeerRole = tc.getRootNode().getDataAfter();
+                    if (maybePeerRole.isPresent()) {
+                        final LeafNode<?> peerRoleLeaf = (LeafNode<?>) maybePeerRole.get();
+                        // FIXME: need codec here
+                        final PeerRole peerRole = (PeerRole) peerRoleLeaf.getValue();
+
+                        // Lookup policy based on role
+                        final AbstractImportPolicy policy = AbstractImportPolicy.forRole(peerRole);
+
+                        // Update lookup map
+                        policies.put(peerId(peerKey), policy);
+                    } else {
+                        policies.remove(peerId(peerKey));
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Maintains the individual routes for a particular table's routes under:
+     *     /bgp-rib/rib/peer/adj-rib-in/tables/routes
+     */
+    private final class TableRouteListener implements DOMDataTreeChangeListener {
+        private final NodeIdentifierWithPredicates tableKey;
+        private final YangInstanceIdentifier target;
+        private final RIBSupport ribSupport;
+        private final PeerId peerId;
+
+        TableRouteListener(final RIBSupport ribSupport, final NodeIdentifierWithPredicates peerKey, final NodeIdentifierWithPredicates tableKey) {
+            this.ribSupport = Preconditions.checkNotNull(ribSupport);
+            this.tableKey = Preconditions.checkNotNull(tableKey);
+
+            // Lookup peer ID
+            this.peerId = (PeerId) Preconditions.checkNotNull(peerKey.getKeyValues().get(PEER_ID));
+
+            // FIXME: need target table ID
+            target = null;
+        }
+
+        private void updateRoutes(final DOMDataWriteTransaction tx, final DataTreeCandidateNode routes, final ContainerNode effectiveAttrs) {
+            final YangInstanceIdentifier routeId = target.node(routes.getIdentifier());
+
+            if (effectiveAttrs != null) {
+                tx.put(LogicalDatastoreType.OPERATIONAL, routeId, routes.getDataAfter().get());
+                tx.put(LogicalDatastoreType.OPERATIONAL, routeId.node(ribSupport.routeAttributes()), effectiveAttrs);
+            } else if (routes.getDataBefore().isPresent()) {
+                tx.delete(LogicalDatastoreType.OPERATIONAL, routeId);
+            }
+
+        }
+
+        @Override
+        public void onDataTreeChanged(final Collection<DataTreeCandidate> changes) {
+            // FIXME: note that we need to detect table clears efficiently and propagate them
+
+            final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction();
+
+            for (DataTreeCandidate tc : changes) {
+                // Lookup per-table attributes from RIBSupport
+                final ContainerNode adverisedAttrs = (ContainerNode) NormalizedNodes.findNode(tc.getRootNode().getDataAfter(), ribSupport.routeAttributes()).orNull();
+                final ContainerNode effectiveAttrs;
+
+                if (adverisedAttrs != null && tc.getRootNode().getDataAfter().isPresent()) {
+                    synchronized (policies) {
+                        final AbstractImportPolicy policy = policies.get(peerId);
+                        effectiveAttrs = policy.effectiveAttributes(adverisedAttrs);
+                    }
+                } else {
+                    effectiveAttrs = null;
+                }
+
+                LOG.debug("Route change {} effective attributes {}", tc.getRootPath(), effectiveAttrs);
+
+                updateRoutes(tx, tc.getRootNode(), effectiveAttrs);
+            }
+
+            tx.submit();
+        }
+    }
+
+    /**
+     * Maintains {@link TableRouteListener} instances.
+     */
+    private final class TableListener implements DOMDataTreeChangeListener {
+        private final Map<YangInstanceIdentifier, ListenerRegistration<?>> routeListeners = new HashMap<>();
+        private final RIBExtensionConsumerContext registry;
+        private final DOMDataTreeChangeService service;
+
+        TableListener(final DOMDataTreeChangeService service, final RIBExtensionConsumerContext registry) {
+            this.registry = Preconditions.checkNotNull(registry);
+            this.service = Preconditions.checkNotNull(service);
+        }
+
+        @Override
+        public void onDataTreeChanged(final Collection<DataTreeCandidate> changes) {
+
+            for (DataTreeCandidate tc : changes) {
+                // Obtain the peer's key
+                final NodeIdentifierWithPredicates peerKey = peerKey(tc.getRootPath());
+
+                // Lookup
+                final NodeIdentifierWithPredicates tableKey = tableKey(tc.getRootPath());
+
+                switch (tc.getRootNode().getModificationType()) {
+                case DELETE:
+                    final ListenerRegistration<?> reg = routeListeners.remove(tc.getRootPath());
+                    if (reg != null) {
+                        reg.close();
+                    }
+                    break;
+                case WRITE:
+                    // FIXME: use codec to translate
+                    final RIBSupport ribSupport = registry.getRIBSupport(null);
+                    if (ribSupport != null) {
+                        final TableRouteListener routeListener = new TableRouteListener(ribSupport, peerKey, tableKey);
+                        final ListenerRegistration<?> r = service.registerDataTreeChangeListener(
+                            new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL,  tc.getRootPath()), routeListener);
+
+                        routeListeners.put(tc.getRootPath(), r);
+                    } else {
+                        LOG.warn("No RIB support for table {}, ignoring advertisements from peer %s", tableKey, peerKey);
+                    }
+                    break;
+                default:
+                    // No-op
+                    break;
+                }
+            }
+        }
+    }
+
+    private final Map<PeerId, AbstractImportPolicy> policies = new HashMap<>();
+    private final DOMTransactionChain chain;
+
+    private EffectiveRibInWriter(final DOMTransactionChain chain) {
+        this.chain = Preconditions.checkNotNull(chain);
+
+        // FIXME: subscribe peerRoleListener, tableListener
+    }
+}
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/IPv4RIBSupport.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/IPv4RIBSupport.java
new file mode 100644 (file)
index 0000000..9dcf714
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.rib.impl;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.destination.destination.type.DestinationIpv4Case;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Routes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.routes.ipv4.routes._case.Ipv4Routes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.routes.ipv4.routes._case.ipv4.routes.Ipv4Route;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.route.Attributes;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+
+final class IPv4RIBSupport extends AbstractIPRIBSupport {
+    private static final IPv4RIBSupport SINGLETON = new IPv4RIBSupport();
+    private final ChoiceNode emptyRoutes = Builders.choiceBuilder()
+            .withNodeIdentifier(new NodeIdentifier(Routes.QNAME))
+            .addChild(Builders.containerBuilder()
+                .withNodeIdentifier(new NodeIdentifier(Ipv4Routes.QNAME))
+                .withChild(ImmutableNodes.mapNodeBuilder(Ipv4Route.QNAME).build()).build()).build();
+    private final NodeIdentifier destination = new NodeIdentifier(DestinationIpv4Case.QNAME);
+    private final NodeIdentifier routes = new NodeIdentifier(Ipv4Routes.QNAME);
+    private final NodeIdentifier route = new NodeIdentifier(Ipv4Route.QNAME);
+    private final NodeIdentifier attributes = new NodeIdentifier(QName.create(Ipv4Route.QNAME, Attributes.QNAME.getLocalName()));
+
+    private static final QName PREFIX_QNAME = QName.create(Ipv4Route.QNAME, "prefix");
+
+    private IPv4RIBSupport() {
+
+    }
+
+    static IPv4RIBSupport getInstance() {
+        return SINGLETON;
+    }
+
+    @Override
+    public ChoiceNode emptyRoutes() {
+        return emptyRoutes;
+    }
+
+    @Override
+    public NodeIdentifier routeAttributes() {
+        return attributes;
+    }
+
+    @Override
+    protected NodeIdentifier destinationIdentifier() {
+        return destination;
+    }
+
+    @Override
+    protected NodeIdentifier routeIdentifier() {
+        return route;
+    }
+
+    @Override
+    protected NodeIdentifier routesIdentifier() {
+        return routes;
+    }
+}
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/IPv6RIBSupport.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/IPv6RIBSupport.java
new file mode 100644 (file)
index 0000000..ca61068
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.rib.impl;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.destination.destination.type.DestinationIpv6Case;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Routes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.routes.ipv6.routes._case.Ipv6Routes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.routes.ipv6.routes._case.ipv6.routes.Ipv6Route;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.route.Attributes;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+
+final class IPv6RIBSupport extends AbstractIPRIBSupport {
+    private static final IPv6RIBSupport SINGLETON = new IPv6RIBSupport();
+    private final ChoiceNode emptyRoutes = Builders.choiceBuilder()
+            .withNodeIdentifier(new NodeIdentifier(Routes.QNAME))
+            .addChild(Builders.containerBuilder()
+                .withNodeIdentifier(new NodeIdentifier(Ipv6Routes.QNAME))
+                .withChild(ImmutableNodes.mapNodeBuilder(Ipv6Route.QNAME).build()).build()).build();
+    private final NodeIdentifier destination = new NodeIdentifier(DestinationIpv6Case.QNAME);
+    private final NodeIdentifier routes = new NodeIdentifier(Ipv6Routes.QNAME);
+    private final NodeIdentifier route = new NodeIdentifier(Ipv6Route.QNAME);
+    private final NodeIdentifier attributes = new NodeIdentifier(QName.create(Ipv6Route.QNAME, Attributes.QNAME.getLocalName()));
+
+    private IPv6RIBSupport() {
+
+    }
+
+    static IPv6RIBSupport getInstance() {
+        return SINGLETON;
+    }
+
+    @Override
+    public ChoiceNode emptyRoutes() {
+        return emptyRoutes;
+    }
+
+    @Override
+    public NodeIdentifier routeAttributes() {
+        return attributes;
+    }
+
+    @Override
+    protected NodeIdentifier destinationIdentifier() {
+        return destination;
+    }
+
+    @Override
+    protected NodeIdentifier routeIdentifier() {
+        return route;
+    }
+
+    @Override
+    protected NodeIdentifier routesIdentifier() {
+        return routes;
+    }
+}
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/LocRibWriter.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/LocRibWriter.java
new file mode 100644 (file)
index 0000000..7f6c35f
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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.rib.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.UnsignedInteger;
+import java.util.Collection;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+
+// FIXME: instantiate for each table, listen on wildcard peer and routes
+@NotThreadSafe
+final class LocRibWriter implements DOMDataTreeChangeListener {
+    private final Map<PathArgument, RouteEntry> routeEntries = new HashMap<>();
+    private final YangInstanceIdentifier target;
+    private final DOMTransactionChain chain;
+    private final RIBSupport ribSupport;
+    private final Long ourAs;
+
+    // FIXME: these maps need to be populated
+    private final Map<PeerRole, Map<PeerId, YangInstanceIdentifier>> peersToUpdate = new EnumMap<>(PeerRole.class);
+    private final Map<PeerId, PeerRole> peers = new HashMap<>();
+
+    LocRibWriter(final RIBSupport ribSupport, final DOMTransactionChain chain, final YangInstanceIdentifier target, final Long ourAs) {
+        this.chain = Preconditions.checkNotNull(chain);
+        this.target = Preconditions.checkNotNull(target);
+        this.ourAs = Preconditions.checkNotNull(ourAs);
+        this.ribSupport = Preconditions.checkNotNull(ribSupport);
+    }
+
+    @Override
+    public void onDataTreeChanged(final Collection<DataTreeCandidate> changes) {
+        /*
+         * We use two-stage processing here in hopes that we avoid duplicate
+         * calculations when multiple peers have changed a particular entry.
+         */
+        final Map<RouteUpdateKey, RouteEntry> toUpdate = new HashMap<>();
+        for (DataTreeCandidate tc : changes) {
+            final YangInstanceIdentifier path = tc.getRootPath();
+            final PathArgument routeId = path.getLastPathArgument();
+            final NodeIdentifierWithPredicates peerKey = EffectiveRibInWriter.peerKey(path);
+            final PeerId peerId = EffectiveRibInWriter.peerId(peerKey);
+            final UnsignedInteger routerId = RouterIds.routerIdForPeerId(peerId);
+
+            RouteEntry entry = routeEntries.get(routeId);
+            if (tc.getRootNode().getDataAfter().isPresent()) {
+                if (entry == null) {
+                    entry = new RouteEntry();
+                    routeEntries.put(routeId, entry);
+                }
+
+                entry.addRoute(routerId, (ContainerNode) tc.getRootNode().getDataAfter().get());
+            } else if (entry != null) {
+                if (entry.removeRoute(routerId)) {
+                    routeEntries.remove(routeId);
+                    entry = null;
+                }
+            }
+
+            toUpdate.put(new RouteUpdateKey(peerId, routeId), entry);
+        }
+
+        final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction();
+
+        // Now walk all updated entries
+        for (Entry<RouteUpdateKey, RouteEntry> e : toUpdate.entrySet()) {
+            final RouteEntry entry = e.getValue();
+            final NormalizedNode<?, ?> value;
+
+            if (entry != null) {
+                if (!entry.selectBest(ourAs)) {
+                    // Best path has not changed, no need to do anything else. Proceed to next route.
+                    continue;
+                }
+
+                value = entry.bestValue(e.getKey().getRouteId());
+            } else {
+                value = null;
+            }
+
+            if (value != null) {
+                tx.put(LogicalDatastoreType.OPERATIONAL, target.node(e.getKey().getRouteId()), value);
+            } else {
+                tx.delete(LogicalDatastoreType.OPERATIONAL, target.node(e.getKey().getRouteId()));
+            }
+
+            /*
+             * We need to keep track of routers and populate adj-ribs-out, too. If we do not, we need to
+             * expose from which client a particular route was learned from in the local RIB, and have
+             * the listener perform filtering.
+             *
+             * We walk the policy set in order to minimize the amount of work we do for multiple peers:
+             * if we have two eBGP peers, for example, there is no reason why we should perform the translation
+             * multiple times.
+             */
+            for (Entry<PeerRole, AbstractExportPolicy> pe : AbstractExportPolicy.POLICIES.entrySet()) {
+                final Map<PeerId, YangInstanceIdentifier> toPeers = peersToUpdate.get(pe.getKey());
+                if (toPeers == null || toPeers.isEmpty()) {
+                    continue;
+                }
+
+                final ContainerNode attributes = null;
+                final PeerId peerId = e.getKey().getPeerId();
+                final ContainerNode effectiveAttributes = pe.getValue().effectiveAttributes(peers.get(peerId), attributes);
+
+                for (Entry<PeerId, YangInstanceIdentifier> pid : toPeers.entrySet()) {
+                    // This points to adj-rib-out for a particlar peer/table combination
+                    final YangInstanceIdentifier routeTarget = pid.getValue().node(e.getKey().getRouteId());
+
+                    if (effectiveAttributes != null && value != null && !peerId.equals(pid.getKey())) {
+                        tx.put(LogicalDatastoreType.OPERATIONAL, routeTarget, value);
+                        tx.put(LogicalDatastoreType.OPERATIONAL, routeTarget.node(ribSupport.routeAttributes()), effectiveAttributes);
+                    } else {
+                        tx.delete(LogicalDatastoreType.OPERATIONAL, routeTarget);
+                    }
+                }
+            }
+        }
+
+        tx.submit();
+    }
+}
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/OffsetMap.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/OffsetMap.java
new file mode 100644 (file)
index 0000000..1dcb46d
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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.rib.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.primitives.UnsignedInteger;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Set;
+
+/**
+ * A map of Router identifier to an offset. Used to maintain a simple
+ * offset-based lookup across multiple {@link RouteEntry} objects,
+ * which share either contributors or consumers.
+ *
+ * We also provide utility reformat methods, which provide access to
+ * array members and array management features.
+ */
+final class OffsetMap {
+    static final OffsetMap EMPTY = new OffsetMap(Collections.<UnsignedInteger>emptySet());
+    private static final LoadingCache<Set<UnsignedInteger>, OffsetMap> OFFSETMAPS = CacheBuilder.newBuilder().weakValues().build(new CacheLoader<Set<UnsignedInteger>, OffsetMap>() {
+        @Override
+        public OffsetMap load(final Set<UnsignedInteger> key) throws Exception {
+            return new OffsetMap(key);
+        }
+    });
+    private static final Comparator<UnsignedInteger> IPV4_COMPARATOR = new Comparator<UnsignedInteger>() {
+        @Override
+        public int compare(final UnsignedInteger o1, final UnsignedInteger o2) {
+            return o1.compareTo(o2);
+        }
+    };
+    private final UnsignedInteger[] routerIds;
+
+    private OffsetMap(final Set<UnsignedInteger> routerIds) {
+        final UnsignedInteger[] array = routerIds.toArray(new UnsignedInteger[0]);
+        Arrays.sort(array, IPV4_COMPARATOR);
+        this.routerIds = array;
+    }
+
+    UnsignedInteger getRouterId(final int offset) {
+        Preconditions.checkArgument(offset >= 0);
+        return this.routerIds[offset];
+    }
+
+    int offsetOf(final UnsignedInteger routerId) {
+        return Arrays.binarySearch(this.routerIds, routerId, IPV4_COMPARATOR);
+    }
+
+    int size() {
+        return this.routerIds.length;
+    }
+
+    OffsetMap with(final UnsignedInteger routerId) {
+        // TODO: we could make this faster if we had an array-backed Set and requiring
+        //       the caller to give us the result of offsetOf() -- as that indicates
+        //       where to insert the new routerId while maintaining the sorted nature
+        //       of the array
+        final Builder<UnsignedInteger> b = ImmutableSet.builder();
+        b.add(this.routerIds);
+        b.add(routerId);
+
+        return OFFSETMAPS.getUnchecked(b.build());
+    }
+
+    <T> T getValue(final T[] array, final int offset) {
+        Preconditions.checkArgument(offset >= 0, "Invalid negative offset {}", offset);
+        return array[offset];
+    }
+
+    <T> void setValue(final T[] array, final int offset, final T value) {
+        Preconditions.checkArgument(offset >= 0, "Invalid negative offset {}", offset);
+        array[offset] = value;
+    }
+
+    <T> T[] expand(final OffsetMap oldOffsets, final T[] oldArray, final int offset) {
+        @SuppressWarnings("unchecked")
+        final T[] ret = (T[]) new Object[this.routerIds.length];
+        final int oldSize = oldOffsets.routerIds.length;
+
+        System.arraycopy(oldArray, 0, ret, 0, offset);
+        System.arraycopy(oldArray, offset, ret, offset + 1, oldSize - offset);
+
+        return ret;
+    }
+}
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RouteEntry.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RouteEntry.java
new file mode 100644 (file)
index 0000000..7768a6b
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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.rib.impl;
+
+import com.google.common.primitives.UnsignedInteger;
+import java.util.Objects;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * A single route entry inside a route table. Maintains the attributes of
+ * from all contributing peers. The information is stored in arrays with a
+ * shared map of offsets for peers to allow lookups. This is needed to
+ * maintain low memory overhead in face of large number of routes and peers,
+ * where individual object overhead becomes the dominating factor.
+ */
+@NotThreadSafe
+final class RouteEntry {
+    private static final ContainerNode[] EMPTY_ATTRIBUTES = new ContainerNode[0];
+
+    private OffsetMap offsets = OffsetMap.EMPTY;
+    private ContainerNode[] values = EMPTY_ATTRIBUTES;
+    private BestPath bestPath;
+
+    void addRoute(final UnsignedInteger routerId, final ContainerNode attributes) {
+        int offset = offsets.offsetOf(routerId);
+        if (offset < 0) {
+            final OffsetMap newOffsets = offsets.with(routerId);
+            offset = newOffsets.offsetOf(routerId);
+
+            final ContainerNode[] newAttributes = newOffsets.expand(offsets, this.values, offset);
+            this.values = newAttributes;
+            this.offsets = newOffsets;
+        }
+
+        offsets.setValue(this.values, offset, attributes);
+    }
+
+    // Indicates whether this was the last route
+    boolean removeRoute(final UnsignedInteger routerId) {
+        if (offsets.size() != 1) {
+            // FIXME: actually shrink the array
+            int offset = offsets.offsetOf(routerId);
+            offsets.setValue(values, offset, null);
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    // Indicates whether best has changed
+    boolean selectBest(final long localAs) {
+        /*
+         * FIXME: optimize flaps by making sure we consider stability of currently-selected route.
+         */
+        final BestPathSelector selector = new BestPathSelector(localAs);
+
+        // Select the best route.
+        for (int i = 0; i < this.offsets.size(); ++i) {
+            final UnsignedInteger routerId = this.offsets.getRouterId(i);
+            final ContainerNode attributes = this.offsets.getValue(this.values, i);
+
+            selector.processPath(routerId, attributes);
+        }
+
+        // Get the newly-selected best path.
+        final BestPath newBestPath = selector.result();
+        // FIXME: run deeper comparison
+        final boolean ret = !Objects.equals(bestPath, newBestPath);
+
+        bestPath = newBestPath;
+        return ret;
+    }
+
+    NormalizedNode<?, ?> bestValue(final PathArgument key) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+}
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RouteUpdateKey.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RouteUpdateKey.java
new file mode 100644 (file)
index 0000000..f0c3a25
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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.rib.impl;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+
+/**
+ * Combined key formed as a concatenation of source peer and route identifiers.
+ * This is used to internally track updates which need to be processed.
+ */
+final class RouteUpdateKey {
+    private final PeerId peerId;
+    private final PathArgument routeId;
+
+    RouteUpdateKey(final PeerId peerId, final PathArgument routeId) {
+        this.peerId = Preconditions.checkNotNull(peerId);
+        this.routeId = Preconditions.checkNotNull(routeId);
+    }
+
+    PeerId getPeerId() {
+        return peerId;
+    }
+
+    PathArgument getRouteId() {
+        return routeId;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + peerId.hashCode();
+        result = prime * result + routeId.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof RouteUpdateKey)) {
+            return false;
+        }
+        RouteUpdateKey other = (RouteUpdateKey) obj;
+        if (!peerId.equals(other.peerId)) {
+            return false;
+        }
+        if (!routeId.equals(other.routeId)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RouterIds.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RouterIds.java
new file mode 100644 (file)
index 0000000..ddaeb43
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.rib.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.net.InetAddresses;
+import com.google.common.primitives.UnsignedInteger;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
+
+final class RouterIds {
+    private static final LoadingCache<String, UnsignedInteger> ROUTER_IDS = CacheBuilder.newBuilder().weakValues().build(new CacheLoader<String, UnsignedInteger>() {
+        @Override
+        public UnsignedInteger load(final String key) {
+            return UnsignedInteger.fromIntBits(InetAddresses.coerceToInteger(InetAddresses.forString(key)));
+        }
+    });
+    private static final LoadingCache<PeerId, UnsignedInteger> BGP_ROUTER_IDS = CacheBuilder.newBuilder().weakValues().build(new CacheLoader<PeerId, UnsignedInteger>() {
+        @Override
+        public UnsignedInteger load(final PeerId key) {
+            return routerIdForAddress(key.getValue().substring(BGP_PREFIX.length()));
+        }
+    });
+    private static final String BGP_PREFIX = "bgp://";
+
+    private RouterIds() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Get a router ID in unsigned integer format from an Ipv4Address. This implementation uses an internal
+     * cache, so the objects can be expected to perform quickly when compared with equals and similar.
+     *
+     * @param address Router ID as a dotted-quad
+     * @return Router ID as an {@link UnsignedInteger}
+     */
+    public static UnsignedInteger routerIdForAddress(final @Nonnull String address) {
+        return ROUTER_IDS.getUnchecked(address);
+    }
+
+    public static UnsignedInteger routerIdForPeerId(final @Nonnull PeerId peerId) {
+        Preconditions.checkArgument(peerId.getValue().startsWith(BGP_PREFIX), "Unhandled peer ID %s", peerId);
+        return BGP_ROUTER_IDS.getUnchecked(peerId);
+    }
+}
index 352420fae2916e8057c2fd9588b4d81aa61d061b..783ce132e15f195f424067eeb3974016e812f416 100644 (file)
@@ -30,7 +30,7 @@ final class SessionRIBsOut extends AbstractAdjRIBsOut implements Runnable {
 
     @Override
     protected boolean writePDU(final Update pdu) {
-        session.sendMessage(pdu);
+        session.writeAndFlush(pdu);
         return session.isWritable();
     }
 
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/TableContext.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/TableContext.java
new file mode 100644 (file)
index 0000000..2641429
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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.rib.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Verify;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import java.util.Set;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.ClusterId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.OriginatorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.PathAttributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Aggregator;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.AsPath;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Communities;
+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.path.attributes.LocalPref;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.MultiExitDisc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Origin;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlri;
+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.rib.rev130925.rib.tables.Attributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Routes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpAggregator;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Community;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ExtendedCommunity;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+
+/**
+ * A context for a single RIB table instance. It is always bound to a particular {@link AdjRibInWriter}.
+ *
+ * FIXME: need a better name once we local-rib and rib-out contexts
+ */
+@NotThreadSafe
+final class TableContext {
+    private static final ContainerNode EMPTY_TABLE_ATTRIBUTES = ImmutableNodes.containerNode(Attributes.QNAME);
+    private static final ContainerNode EMPTY_ROUTE_ATTRIBUTES = ImmutableNodes.containerNode(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.route.Attributes.QNAME);
+    private static final Set<Class<? extends DataObject>> ATTRIBUTE_CACHEABLES;
+
+    static {
+        final Builder<Class<? extends DataObject>> acb = ImmutableSet.builder();
+        acb.add(Aggregator.class);
+        acb.add(BgpAggregator.class);
+        acb.add(AsPath.class);
+        acb.add(ClusterId.class);
+        acb.add(Community.class);
+        acb.add(Communities.class);
+        acb.add(ExtendedCommunity.class);
+        acb.add(ExtendedCommunities.class);
+        acb.add(LocalPref.class);
+        acb.add(MultiExitDisc.class);
+        acb.add(Origin.class);
+        acb.add(OriginatorId.class);
+        ATTRIBUTE_CACHEABLES = acb.build();
+    }
+
+    private final YangInstanceIdentifier tableId;
+    private final RIBSupport tableSupport;
+    private final Object attributeCodec;
+    private final Object nlriCodec;
+
+    TableContext(final RIBSupport tableSupport, final YangInstanceIdentifier tableId) {
+        this.tableSupport = Preconditions.checkNotNull(tableSupport);
+        this.tableId = Preconditions.checkNotNull(tableId);
+
+        final Builder<Class<? extends DataObject>> acb = ImmutableSet.builder();
+        acb.addAll(ATTRIBUTE_CACHEABLES);
+        acb.addAll(tableSupport.cacheableAttributeObjects());
+
+        // FIXME: new Codec.create(acb.build(), tableSupport.cacheableNlriObjects());
+        attributeCodec = null;
+
+        // FIXME: new Codec.create(tableSupport.cacheableNlriObjects());
+        nlriCodec = null;
+    }
+
+    YangInstanceIdentifier getTableId() {
+        return tableId;
+    }
+
+    void clearTable(final DOMDataWriteTransaction tx) {
+        final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> tb =
+                ImmutableNodes.mapEntryBuilder().withNodeIdentifier((NodeIdentifierWithPredicates)tableId.getLastPathArgument()).withChild(EMPTY_TABLE_ATTRIBUTES);
+
+        final ChoiceNode routes = tableSupport.emptyRoutes();
+        Verify.verifyNotNull(routes, "Null empty routes in %s", this);
+        Verify.verify(Routes.QNAME.equals(routes.getNodeType()), "Empty routes have unexpected identifier %s, expected %s", routes.getNodeType(), Routes.QNAME);
+
+        tx.put(LogicalDatastoreType.OPERATIONAL, tableId, tb.withChild(routes).build());
+    }
+
+    void removeTable(final DOMDataWriteTransaction tx) {
+        tx.delete(LogicalDatastoreType.OPERATIONAL, tableId);
+    }
+
+    void writeRoutes(final Object codecFactory, final DOMDataWriteTransaction tx, final MpReachNlri nlri, final PathAttributes attributes) {
+
+        // FIXME: run the decoder process
+        final ContainerNode domNlri = (ContainerNode) nlriCodec;
+
+        // FIXME: run the decoder process
+        final ContainerNode domAttributes = (ContainerNode) attributeCodec;
+        final ContainerNode routeAttributes = Builders.containerBuilder(EMPTY_ROUTE_ATTRIBUTES).withValue(domAttributes.getValue()).build();
+
+        tableSupport.putRoutes(tx, tableId, domNlri, routeAttributes);
+    }
+
+    void removeRoutes(final Object object, final DOMDataWriteTransaction tx, final MpUnreachNlri nlri) {
+        // FIXME: run the decoder process
+        final ContainerNode domNlri = (ContainerNode) nlriCodec;
+
+        tableSupport.deleteRoutes(tx, tableId, domNlri);
+    }
+}
index f6fcd1d849ec7577f9734b7f4f9ce97914b5ee38..e59a9765eea3c70419727e159faac6dd334c204a 100644 (file)
@@ -10,11 +10,11 @@ package org.opendaylight.protocol.bgp.rib.impl;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.Matchers.any;
-
 import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.CheckedFuture;
 import io.netty.channel.Channel;
+import io.netty.channel.DefaultChannelPromise;
 import io.netty.channel.EventLoop;
 import java.math.BigInteger;
 import java.net.InetSocketAddress;
@@ -109,6 +109,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.type
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.IsoSystemIdentifier;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.Notification;
 
 public class ApplicationPeerTest {
 
@@ -272,6 +273,7 @@ public class ApplicationPeerTest {
         Mockito.doReturn(null).when(this.eventLoop).schedule(any(Runnable.class), any(long.class), any(TimeUnit.class));
         Mockito.doReturn(Boolean.TRUE).when(this.channel).isWritable();
         Mockito.doReturn(null).when(this.channel).close();
+        Mockito.doReturn(new DefaultChannelPromise(channel)).when(this.channel).writeAndFlush(any(Notification.class));
 
         Mockito.doReturn(new InetSocketAddress("localhost", 12345)).when(this.channel).remoteAddress();
         Mockito.doReturn(new InetSocketAddress("localhost", 12345)).when(this.channel).localAddress();
index 09ef537bf0a685116da01c368235ff6cd4fc7d75..7f640f98d28c00569bb2978b137130c6abdaebef 100644 (file)
@@ -27,7 +27,7 @@ public class SpeakerSessionMock extends BGPSessionImpl {
     }
 
     @Override
-    public void sendMessage(final Notification msg) {
+    public void writeAndFlush(final Notification msg) {
         this.setLastMessageSentAt(System.nanoTime());
         this.client.onMessage(this, msg);
     }
index 1f99ae3c46a086f6960dc1d9d256050956bb6dd0..c3d93541bc6da0a48cc46b1714efa99f5b1d0164 100644 (file)
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>protocol-framework</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-core-api</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
diff --git a/bgp/rib-spi/src/main/java/org/opendaylight/controller/config/yang/bgp/rib/spi/AbstractRIBSupport.java b/bgp/rib-spi/src/main/java/org/opendaylight/controller/config/yang/bgp/rib/spi/AbstractRIBSupport.java
new file mode 100644 (file)
index 0000000..4bc6ce2
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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.controller.config.yang.bgp.rib.spi;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.destination.DestinationType;
+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.unreach.nlri.WithdrawnRoutes;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+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.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Beta
+public abstract class AbstractRIBSupport implements RIBSupport {
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractRIBSupport.class);
+    private static final NodeIdentifier ADVERTIZED_ROUTES = new NodeIdentifier(AdvertizedRoutes.QNAME);
+    private static final NodeIdentifier WITHDRAWN_ROUTES = new NodeIdentifier(WithdrawnRoutes.QNAME);
+    private static final NodeIdentifier DESTINATION_TYPE = new NodeIdentifier(DestinationType.QNAME);
+
+    protected AbstractRIBSupport() {
+
+    }
+
+    protected abstract NodeIdentifier destinationIdentifier();
+    protected abstract void deleteDestinationRoutes(DOMDataWriteTransaction tx, YangInstanceIdentifier tableId, ContainerNode destination);
+    protected abstract void putDestinationRoutes(DOMDataWriteTransaction tx, YangInstanceIdentifier tableId, ContainerNode destination, ContainerNode attributes);
+
+    private static ContainerNode getDestination(final DataContainerChild<? extends PathArgument, ?> routes, final NodeIdentifier destinationId) {
+        if (routes instanceof ContainerNode) {
+            final Optional<DataContainerChild<? extends PathArgument, ?>> maybeDestination = ((ContainerNode)routes).getChild(DESTINATION_TYPE);
+            if (maybeDestination.isPresent()) {
+                final DataContainerChild<? extends PathArgument, ?> destination = maybeDestination.get();
+                if (destination instanceof ChoiceNode) {
+                    final Optional<DataContainerChild<? extends PathArgument, ?>> maybeRet = ((ChoiceNode)destination).getChild(destinationId);
+                    if (maybeRet.isPresent()) {
+                        final DataContainerChild<? extends PathArgument, ?> ret = maybeRet.get();
+                        if (ret instanceof ContainerNode) {
+                            return (ContainerNode)ret;
+                        } else {
+                            LOG.debug("Specified node {} is not a container, ignoring it", ret);
+                        }
+                    } else {
+                        LOG.debug("Specified container {} is not present in destination {}", destinationId, destination);
+                    }
+                } else {
+                    LOG.warn("Destination {} is not a choice, ignoring it", destination);
+                }
+            } else {
+                LOG.debug("Destination is not present in routes {}", routes);
+            }
+        } else {
+            LOG.warn("Advertized routes {} are not a container, ignoring it", routes);
+        }
+
+        return null;
+    }
+
+    @Override
+    public final void deleteRoutes(final DOMDataWriteTransaction tx, final YangInstanceIdentifier tableId, final ContainerNode nlri) {
+        final Optional<DataContainerChild<? extends PathArgument, ?>> maybeRoutes = nlri.getChild(WITHDRAWN_ROUTES);
+        if (maybeRoutes.isPresent()) {
+            final ContainerNode destination = getDestination(maybeRoutes.get(), destinationIdentifier());
+            if (destination != null) {
+                deleteDestinationRoutes(tx, tableId, destination);
+            }
+        } else {
+            LOG.debug("Withdrawn routes are not present in NLRI {}", nlri);
+        }
+    }
+
+    @Override
+    public final void putRoutes(final DOMDataWriteTransaction tx, final YangInstanceIdentifier tableId, final ContainerNode nlri, final ContainerNode attributes) {
+        final Optional<DataContainerChild<? extends PathArgument, ?>> maybeRoutes = nlri.getChild(ADVERTIZED_ROUTES);
+        if (maybeRoutes.isPresent()) {
+            final ContainerNode destination = getDestination(maybeRoutes.get(), destinationIdentifier());
+            if (destination != null) {
+                putDestinationRoutes(tx, tableId, destination, attributes);
+            }
+        } else {
+            LOG.debug("Advertized routes are not present in NLRI {}", nlri);
+        }
+    }
+}
diff --git a/bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/AbstractRIBSupportRegistration.java b/bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/AbstractRIBSupportRegistration.java
new file mode 100644 (file)
index 0000000..7c51d19
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * 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.rib.spi;
+
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+
+public abstract class AbstractRIBSupportRegistration<T extends RIBSupport> extends AbstractObjectRegistration<T> implements RIBSupportRegistration<T> {
+    protected AbstractRIBSupportRegistration(final T instance) {
+        super(instance);
+    }
+}
index 74c681af9de2316a83b37c80686c741e1a171c35..2b74785de927cdebb7c63f6c42fc00042d6fdf66 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.protocol.bgp.rib.spi;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.AddressFamily;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.SubsequentAddressFamily;
 
@@ -26,4 +27,21 @@ public interface RIBExtensionConsumerContext {
      *         not implemented.
      */
     @Nullable AdjRIBsFactory getAdjRIBsInFactory(@Nonnull Class<? extends AddressFamily> afi, @Nonnull Class<? extends SubsequentAddressFamily> safi);
+
+    /**
+     * Acquire a RIB implementation factory for a AFI/SAFI combination.
+     * @param key AFI/SAFI key
+     * @return RIBSupport instance, or null if the AFI/SAFI is
+     *         not implemented.
+     */
+    @Nullable RIBSupport getRIBSupport(@Nonnull TablesKey key);
+
+    /**
+     * Acquire a RIB implementation factory for a AFI/SAFI combination.
+     * @param afi Address Family Identifier
+     * @param safi Subsequent Address Family identifier
+     * @return RIBSupport instance, or null if the AFI/SAFI is
+     *         not implemented.
+     */
+    @Nullable RIBSupport getRIBSupport(@Nonnull Class<? extends AddressFamily> afi, @Nonnull Class<? extends SubsequentAddressFamily> safi);
 }
\ No newline at end of file
index 0995b85e046650f9fbb5c05a78063dc3ffb55a8c..9eca6605dc34d16f71578366252f693aaa8222e4 100644 (file)
@@ -26,4 +26,15 @@ public interface RIBExtensionProviderContext extends RIBExtensionConsumerContext
      */
     AutoCloseable registerAdjRIBsInFactory(Class<? extends AddressFamily> afi, Class<? extends SubsequentAddressFamily> safi,
             AdjRIBsFactory factory);
+
+    /**
+     * Register a RIBSupport instance for a particular AFI/SAFI combination.
+     *
+     * @param afi Address Family identifier
+     * @param safi Subsequent Address Family identifier
+     * @param support RIBSupport instance
+     * @return Registration handle. Call {@link RIBSupportRegistration#close()} method to remove it.
+     * @throws NullPointerException if any of the arguments is null
+     */
+    <T extends RIBSupport> RIBSupportRegistration<T> registerRIBSupport(Class<? extends AddressFamily> afi, Class<? extends SubsequentAddressFamily> safi, T support);
 }
\ No newline at end of file
diff --git a/bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/RIBSupport.java b/bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/RIBSupport.java
new file mode 100644 (file)
index 0000000..fea3928
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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.rib.spi;
+
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+
+public interface RIBSupport {
+    /**
+     * Return the table-type-specific empty routes container, as augmented into the
+     * bgp-rib model under /rib/tables/routes choice node. This needs to include all
+     * the skeleton nodes under which the individual routes will be stored.
+     *
+     * @return Protocol-specific case in the routes choice, may not be null.
+     */
+    @Nonnull ChoiceNode emptyRoutes();
+    @Nonnull NodeIdentifier routeAttributes();
+
+    @Nonnull Collection<Class<? extends DataObject>> cacheableAttributeObjects();
+    @Nonnull Collection<Class<? extends DataObject>> cacheableNlriObjects();
+    void deleteRoutes(@Nonnull DOMDataWriteTransaction tx, @Nonnull YangInstanceIdentifier tableId, @Nonnull ContainerNode nlri);
+    void putRoutes(@Nonnull DOMDataWriteTransaction tx, @Nonnull YangInstanceIdentifier tableId, @Nonnull ContainerNode nlri, @Nonnull ContainerNode attributes);
+
+}
diff --git a/bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/RIBSupportRegistration.java b/bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/RIBSupportRegistration.java
new file mode 100644 (file)
index 0000000..1660b7c
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * 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.rib.spi;
+
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+
+/**
+ * A registration of a {@link RIBSupport} instance.
+ *
+ * @param <T> {@link RIBSupport} type
+ */
+public interface RIBSupportRegistration<T extends RIBSupport> extends ObjectRegistration<T> {
+    @Override
+    void close();
+}
index bea86bce9433b307fb2a300a389745b79937c148..41e4d2a98012942f3cdccac5a31d0a0366f37690 100644 (file)
@@ -7,16 +7,17 @@
  */
 package org.opendaylight.protocol.bgp.rib.spi;
 
-import java.util.Map;
+import com.google.common.base.Preconditions;
 import java.util.concurrent.ConcurrentHashMap;
-
+import java.util.concurrent.ConcurrentMap;
 import org.opendaylight.protocol.concepts.AbstractRegistration;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.AddressFamily;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.SubsequentAddressFamily;
 
 public class SimpleRIBExtensionProviderContext implements RIBExtensionProviderContext {
-    private final Map<TablesKey, AdjRIBsFactory> factories = new ConcurrentHashMap<>();
+    private final ConcurrentMap<TablesKey, AdjRIBsFactory> factories = new ConcurrentHashMap<>();
+    private final ConcurrentMap<TablesKey, RIBSupport> supports = new ConcurrentHashMap<>();
 
     @Override
     public final synchronized AbstractRegistration registerAdjRIBsInFactory(final Class<? extends AddressFamily> afi,
@@ -29,11 +30,10 @@ public class SimpleRIBExtensionProviderContext implements RIBExtensionProviderCo
 
         this.factories.put(key, factory);
 
-        final Object lock = this;
         return new AbstractRegistration() {
             @Override
             protected void removeRegistration() {
-                synchronized (lock) {
+                synchronized (SimpleRIBExtensionProviderContext.this) {
                     SimpleRIBExtensionProviderContext.this.factories.remove(key);
                 }
             }
@@ -45,4 +45,30 @@ public class SimpleRIBExtensionProviderContext implements RIBExtensionProviderCo
             final Class<? extends SubsequentAddressFamily> safi) {
         return this.factories.get(new TablesKey(afi, safi));
     }
+
+    @Override
+    public <T extends RIBSupport> RIBSupportRegistration<T> registerRIBSupport(final Class<? extends AddressFamily> afi,
+            final Class<? extends SubsequentAddressFamily> safi, final T support) {
+        final TablesKey key = new TablesKey(afi, safi);
+
+        final RIBSupport prev = this.supports.putIfAbsent(key, support);
+        Preconditions.checkArgument(prev == null, "AFI %s SAFI %s is already registered with %s", afi, safi, prev);
+
+        return new AbstractRIBSupportRegistration<T>(support) {
+            @Override
+            protected void removeRegistration() {
+                SimpleRIBExtensionProviderContext.this.supports.remove(key);
+            }
+        };
+    }
+
+    @Override
+    public RIBSupport getRIBSupport(final Class<? extends AddressFamily> afi, final Class<? extends SubsequentAddressFamily> safi) {
+        return getRIBSupport(new TablesKey(afi, safi));
+    }
+
+    @Override
+    public RIBSupport getRIBSupport(final TablesKey key) {
+        return this.supports.get(Preconditions.checkNotNull(key));
+    }
 }
index 902869146da685ad030e1da994f84562d652fde3..7ab1830980dccb6e6b4976750aee0860eca097d5 100644 (file)
@@ -54,6 +54,7 @@
         <bundle>mvn:org.opendaylight.bgpcep/bgp-parser-api/{{VERSION}}</bundle>
         <bundle>mvn:org.opendaylight.bgpcep/bgp-concepts/{{VERSION}}</bundle>
         <feature version='${protocol-framework.version}'>odl-protocol-framework</feature>
+        <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
         <bundle>mvn:org.opendaylight.bgpcep/bgp-rib-api/{{VERSION}}</bundle>
         <bundle>mvn:org.opendaylight.bgpcep/bgp-rib-spi/{{VERSION}}</bundle>
     </feature>
index ff07647b083d02e12bacc5f96c116cf229c830d9..a5edec3cdf244d972639f12ec1c5bfdca9af9065 100644 (file)
@@ -66,7 +66,7 @@ public class AbstractPcepOsgiTest {
                 TestHelper.mdSalCoreBundles(),
 
                 TestHelper.bindingAwareSalBundles(), TestHelper.configMinumumBundles(), TestHelper.baseModelBundles(),
-                TestHelper.flowCapableModelBundles(), TestHelper.junitAndMockitoBundles());
+                TestHelper.junitAndMockitoBundles());
     }
 
     private Option pcepModules() {
index d98c8a94fd3b8219defd80ac3cd297e61e7a0713..f7b9f46005eb2def01927bd13788458c1f4d2044 100644 (file)
@@ -42,7 +42,6 @@
         <nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>
         <sitedeploy>dav:http://nexus.opendaylight.org/content/sites/site</sitedeploy>
 
-        <maven.dependency.version>2.8</maven.dependency.version>
         <maven.info.reports.version>2.7</maven.info.reports.version>
 
         <!-- YANG tools artifacts -->
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-dependency-plugin</artifactId>
-                <version>${maven.dependency.version}</version>
                 <configuration>
                     <failOnWarning>true</failOnWarning>
                     <ignoreNonCompile>true</ignoreNonCompile>
                                         </goals>
                                     </pluginExecutionFilter>
                                     <action>
-                                        <ignore />
+                                        <execute />
                                     </action>
                                 </pluginExecution>
                                 <pluginExecution>
                                         <ignore/>
                                     </action>
                                 </pluginExecution>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>org.apache.maven.plugins</groupId>
+                                        <artifactId>maven-checkstyle-plugin</artifactId>
+                                        <versionRange>[2.13,)</versionRange>
+                                        <goals>
+                                            <goal>check</goal>
+                                        </goals>
+                                    </pluginExecutionFilter>
+                                    <action>
+                                        <execute />
+                                    </action>
+                                </pluginExecution>
                             </pluginExecutions>
                         </lifecycleMappingMetadata>
                     </configuration>
index cbdb9815b24ca90a2c86c340c82978cb7078c3ee..bd55317c29db3aa22e2898ab1093447b47370c2f 100644 (file)
@@ -13,13 +13,12 @@ import com.google.common.base.Preconditions;
 import com.google.common.primitives.UnsignedBytes;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.ietf.stateful07.Stateful07LspObjectParser;
 import org.opendaylight.protocol.pcep.spi.ObjectUtil;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.TlvRegistry;
 import org.opendaylight.protocol.pcep.spi.VendorInformationTlvRegistry;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.Lsp1;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.Lsp1Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.OperationalStatus;
@@ -35,7 +34,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.typ
  */
 public class CInitiated00LspObjectParser extends Stateful07LspObjectParser {
 
-    private static final int CREATE_FLAG_OFFSET = 8;
+    private static final int CREATE_FLAG_OFFSET = 4;
 
     public CInitiated00LspObjectParser(final TlvRegistry tlvReg, final VendorInformationTlvRegistry viTlvReg) {
         super(tlvReg, viTlvReg);
@@ -48,17 +47,17 @@ public class CInitiated00LspObjectParser extends Stateful07LspObjectParser {
         builder.setIgnore(header.isIgnore());
         builder.setProcessingRule(header.isProcessingRule());
         final int[] plspIdRaw = new int[] { bytes.readUnsignedByte(), bytes.readUnsignedByte(), bytes.getUnsignedByte(2), };
-        builder.setPlspId(new PlspId((long) ((plspIdRaw[0] << TWELVE_BITS_SHIFT) | (plspIdRaw[1] << FOUR_BITS_SHIFT) | (plspIdRaw[2] >> FOUR_BITS_SHIFT))));
-        final BitSet flags = ByteArray.bytesToBitSet(ByteArray.readBytes(bytes, 2));
-        builder.setDelegate(flags.get(DELEGATE_FLAG_OFFSET));
-        builder.setSync(flags.get(SYNC_FLAG_OFFSET));
-        builder.setRemove(flags.get(REMOVE_FLAG_OFFSET));
-        builder.setAdministrative(flags.get(ADMINISTRATIVE_FLAG_OFFSET));
+        builder.setPlspId(new PlspId((long) ((plspIdRaw[0] << FLAGS_SIZE) | (plspIdRaw[1] << FOUR_BITS_SHIFT) | (plspIdRaw[2] >> FOUR_BITS_SHIFT))));
+        final BitArray flags = BitArray.valueOf(bytes, FLAGS_SIZE);
+        builder.setDelegate(flags.get(DELEGATE));
+        builder.setSync(flags.get(SYNC));
+        builder.setRemove(flags.get(REMOVE));
+        builder.setAdministrative(flags.get(ADMINISTRATIVE));
         builder.addAugmentation(Lsp1.class, new Lsp1Builder().setCreate(flags.get(CREATE_FLAG_OFFSET)).build());
         short s = 0;
-        s |= flags.get(OPERATIONAL_OFFSET + 2) ? 1 : 0;
-        s |= (flags.get(OPERATIONAL_OFFSET + 1) ? 1 : 0) << 1;
-        s |= (flags.get(OPERATIONAL_OFFSET) ? 1 : 0) << 2;
+        s |= flags.get(OPERATIONAL + 2) ? 1 : 0;
+        s |= (flags.get(OPERATIONAL + 1) ? 1 : 0) << 1;
+        s |= (flags.get(OPERATIONAL) ? 1 : 0) << 2;
         builder.setOperational(OperationalStatus.forValue(s));
         final TlvsBuilder b = new TlvsBuilder();
         parseTlvs(b, bytes.slice());
@@ -73,20 +72,12 @@ public class CInitiated00LspObjectParser extends Stateful07LspObjectParser {
         final ByteBuf body = Unpooled.buffer();
         Preconditions.checkArgument(specObj.getPlspId() != null, "PLSP-ID not present");
         writeMedium(specObj.getPlspId().getValue().intValue() << FOUR_BITS_SHIFT, body);
-        final BitSet flags = new BitSet(2 * Byte.SIZE);
-        if (specObj.isDelegate() != null) {
-            flags.set(DELEGATE_FLAG_OFFSET, specObj.isDelegate());
-        }
-        if (specObj.isRemove() != null) {
-            flags.set(REMOVE_FLAG_OFFSET, specObj.isRemove());
-        }
-        if (specObj.isSync() != null) {
-            flags.set(SYNC_FLAG_OFFSET, specObj.isSync());
-        }
-        if (specObj.isAdministrative() != null) {
-            flags.set(ADMINISTRATIVE_FLAG_OFFSET, specObj.isAdministrative());
-        }
-        if (specObj.getAugmentation(Lsp1.class) != null && specObj.getAugmentation(Lsp1.class).isCreate() != null) {
+        final BitArray flags = new BitArray(FLAGS_SIZE);
+        flags.set(DELEGATE, specObj.isDelegate());
+        flags.set(REMOVE, specObj.isRemove());
+        flags.set(SYNC, specObj.isSync());
+        flags.set(ADMINISTRATIVE, specObj.isAdministrative());
+        if (specObj.getAugmentation(Lsp1.class) != null) {
             flags.set(CREATE_FLAG_OFFSET, specObj.getAugmentation(Lsp1.class).isCreate());
         }
         byte op = 0;
@@ -94,7 +85,9 @@ public class CInitiated00LspObjectParser extends Stateful07LspObjectParser {
             op = UnsignedBytes.checkedCast(specObj.getOperational().getIntValue());
             op = (byte) (op << FOUR_BITS_SHIFT);
         }
-        body.writeByte(ByteArray.bitSetToBytes(flags, 2)[1] | op);
+        final byte[] res = flags.array();
+        res[res.length -1] = (byte) (res[res.length -1] | op);
+        body.writeByte(res[res.length -1]);
         serializeTlvs(specObj.getTlvs(), body);
         ObjectUtil.formatSubobject(TYPE, CLASS, object.isProcessingRule(), object.isIgnore(), body, buffer);
     }
index f0bca39e42eab9abd739799a3b0f9f86f29b98bb..42c726fa9363ce406baeb5039a13c05ee3e0d09f 100644 (file)
@@ -7,19 +7,17 @@
  */
 package org.opendaylight.protocol.pcep.ietf.initiated00;
 
-import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeBitSet;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeUnsignedInt;
 
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.ietf.stateful07.Stateful07SrpObjectParser;
 import org.opendaylight.protocol.pcep.spi.ObjectUtil;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.TlvRegistry;
 import org.opendaylight.protocol.pcep.spi.VendorInformationTlvRegistry;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.Srp1;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.Srp1Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.SrpIdNumber;
@@ -50,7 +48,7 @@ public class CInitiated00SrpObjectParser extends Stateful07SrpObjectParser {
         final SrpBuilder builder = new SrpBuilder();
         builder.setIgnore(header.isIgnore());
         builder.setProcessingRule(header.isProcessingRule());
-        final BitSet flags = ByteArray.bytesToBitSet(ByteArray.readBytes(bytes, FLAGS_SIZE));
+        final BitArray flags = BitArray.valueOf(bytes, FLAGS_SIZE);
         builder.addAugmentation(Srp1.class, new Srp1Builder().setRemove(flags.get(REMOVE_FLAG)).build());
         builder.setOperationId(new SrpIdNumber(bytes.readUnsignedInt()));
         final TlvsBuilder tlvsBuilder = new TlvsBuilder();
@@ -64,11 +62,11 @@ public class CInitiated00SrpObjectParser extends Stateful07SrpObjectParser {
         Preconditions.checkArgument(object instanceof Srp, "Wrong instance of PCEPObject. Passed %s. Needed SrpObject.", object.getClass());
         final Srp srp = (Srp) object;
         final ByteBuf body = Unpooled.buffer();
-        final BitSet flags = new BitSet(FLAGS_SIZE * Byte.SIZE);
-        if (srp.getAugmentation(Srp1.class) != null && srp.getAugmentation(Srp1.class).isRemove()) {
+        final BitArray flags = new BitArray(FLAGS_SIZE);
+        if (srp.getAugmentation(Srp1.class) != null) {
             flags.set(REMOVE_FLAG, srp.getAugmentation(Srp1.class).isRemove());
         }
-        writeBitSet(flags, FLAGS_SIZE, body);
+        flags.toByteBuf(body);
         Preconditions.checkArgument(srp.getOperationId() != null, "OperationId is mandatory.");
         writeUnsignedInt(srp.getOperationId().getValue(), body);
         serializeTlvs(srp.getTlvs(), body);
index 27ce9f9bd3c9529eee0a635ba0a5898a1498b5d2..493b9e7bd3a5854d4cd691d369d57b458bf17c1b 100644 (file)
@@ -7,16 +7,13 @@
  */
 package org.opendaylight.protocol.pcep.ietf.initiated00;
 
-import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeBitSet;
-
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.ietf.stateful07.Stateful07StatefulCapabilityTlvParser;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.TlvUtil;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.Stateful1;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev131126.Stateful1Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.stateful.capability.tlv.Stateful;
@@ -35,15 +32,13 @@ public final class CInitiated00StatefulCapabilityTlvParser extends Stateful07Sta
         if (buffer == null) {
             return null;
         }
-        if (buffer.readableBytes() < FLAGS_F_LENGTH) {
+        if (buffer.readableBytes() < FLAGS_F_LENGTH / Byte.SIZE) {
             throw new PCEPDeserializerException("Wrong length of array of bytes. Passed: " + buffer.readableBytes() + "; Expected: >= "
-                    + FLAGS_F_LENGTH + ".");
+                    + FLAGS_F_LENGTH / Byte.SIZE + ".");
         }
-        final BitSet flags = ByteArray.bytesToBitSet(ByteArray.readBytes(buffer, FLAGS_F_LENGTH));
-
+        final BitArray flags = BitArray.valueOf(buffer, FLAGS_F_LENGTH);
         final StatefulBuilder sb = new StatefulBuilder();
         sb.setLspUpdateCapability(flags.get(U_FLAG_OFFSET));
-
         if (flags.get(I_FLAG_OFFSET)) {
             sb.addAugmentation(Stateful1.class, new Stateful1Builder().setInitiation(Boolean.TRUE).build());
         }
@@ -54,16 +49,12 @@ public final class CInitiated00StatefulCapabilityTlvParser extends Stateful07Sta
     public void serializeTlv(final Tlv tlv, final ByteBuf buffer) {
         Preconditions.checkArgument(tlv instanceof Stateful, "StatefulCapabilityTlv is mandatory.");
         final Stateful sct = (Stateful) tlv;
-        final ByteBuf body = Unpooled.buffer();
-        final BitSet flags = new BitSet(FLAGS_F_LENGTH * Byte.SIZE);
+        final BitArray flags = new BitArray(FLAGS_F_LENGTH);
         final Stateful1 sfi = sct.getAugmentation(Stateful1.class);
         if (sfi != null) {
             flags.set(I_FLAG_OFFSET, sfi.isInitiation());
         }
-        if (sct.isLspUpdateCapability() != null) {
-            flags.set(U_FLAG_OFFSET, sct.isLspUpdateCapability());
-        }
-        writeBitSet(flags, FLAGS_F_LENGTH, body);
-        TlvUtil.formatTlv(TYPE, body, buffer);
+        flags.set(U_FLAG_OFFSET, sct.isLspUpdateCapability());
+        TlvUtil.formatTlv(TYPE, Unpooled.wrappedBuffer(flags.array()), buffer);
     }
 }
index c4a3ab56382f5cd3783cce9abf4603045409d1bf..824659286faa66fc6957ea5a7f9e6f72442e3ffb 100644 (file)
@@ -13,14 +13,13 @@ import com.google.common.base.Preconditions;
 import com.google.common.primitives.UnsignedBytes;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import java.util.List;
 import org.opendaylight.protocol.pcep.spi.AbstractObjectWithTlvsParser;
 import org.opendaylight.protocol.pcep.spi.ObjectUtil;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.TlvRegistry;
 import org.opendaylight.protocol.pcep.spi.VendorInformationTlvRegistry;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.OperationalStatus;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.PlspId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.error.code.tlv.LspErrorCode;
@@ -46,26 +45,17 @@ public class Stateful07LspObjectParser extends AbstractObjectWithTlvsParser<Tlvs
 
     public static final int TYPE = 1;
 
-    /*
-     * offset of TLVs offset of other fields are not defined as constants
-     * because of non-standard mapping of bits
-     */
-    protected static final int TLVS_OFFSET = 4;
-
     /*
      * 12b extended to 16b so first 4b are restricted (belongs to LSP ID)
      */
-    protected static final int DELEGATE_FLAG_OFFSET = 15;
-    protected static final int SYNC_FLAG_OFFSET = 14;
-    protected static final int REMOVE_FLAG_OFFSET = 13;
-    protected static final int ADMINISTRATIVE_FLAG_OFFSET = 12;
-    protected static final int OPERATIONAL_OFFSET = 9;
+    protected static final int DELEGATE = 11;
+    protected static final int SYNC = 10;
+    protected static final int REMOVE = 9;
+    protected static final int ADMINISTRATIVE = 8;
+    protected static final int OPERATIONAL = 5;
 
     protected static final int FOUR_BITS_SHIFT = 4;
-    protected static final int TWELVE_BITS_SHIFT = 12;
-    protected static final int BODY_LENGTH = 4;
-    protected static final int FLAGS_INDEX = 3;
-    protected static final int OP_VALUE_BITS_OFFSET = 7;
+    protected static final int FLAGS_SIZE = 12;
 
     public Stateful07LspObjectParser(final TlvRegistry tlvReg, final VendorInformationTlvRegistry viTlvReg) {
         super(tlvReg, viTlvReg);
@@ -78,16 +68,16 @@ public class Stateful07LspObjectParser extends AbstractObjectWithTlvsParser<Tlvs
         builder.setIgnore(header.isIgnore());
         builder.setProcessingRule(header.isProcessingRule());
         final int[] plspIdRaw = new int[] { bytes.readUnsignedByte(), bytes.readUnsignedByte(), bytes.getUnsignedByte(2), };
-        builder.setPlspId(new PlspId((long) ((plspIdRaw[0] << TWELVE_BITS_SHIFT) | (plspIdRaw[1] << FOUR_BITS_SHIFT) | (plspIdRaw[2] >> FOUR_BITS_SHIFT))));
-        final BitSet flags = ByteArray.bytesToBitSet(ByteArray.readBytes(bytes, 2));
-        builder.setDelegate(flags.get(DELEGATE_FLAG_OFFSET));
-        builder.setSync(flags.get(SYNC_FLAG_OFFSET));
-        builder.setRemove(flags.get(REMOVE_FLAG_OFFSET));
-        builder.setAdministrative(flags.get(ADMINISTRATIVE_FLAG_OFFSET));
+        builder.setPlspId(new PlspId((long) ((plspIdRaw[0] << FLAGS_SIZE) | (plspIdRaw[1] << FOUR_BITS_SHIFT) | (plspIdRaw[2] >> FOUR_BITS_SHIFT))));
+        final BitArray flags = BitArray.valueOf(bytes, FLAGS_SIZE);
+        builder.setDelegate(flags.get(DELEGATE));
+        builder.setSync(flags.get(SYNC));
+        builder.setRemove(flags.get(REMOVE));
+        builder.setAdministrative(flags.get(ADMINISTRATIVE));
         short s = 0;
-        s |= flags.get(OPERATIONAL_OFFSET + 2) ? 1 : 0;
-        s |= (flags.get(OPERATIONAL_OFFSET + 1) ? 1 : 0) << 1;
-        s |= (flags.get(OPERATIONAL_OFFSET) ? 1 : 0) << 2;
+        s |= flags.get(OPERATIONAL + 2) ? 1 : 0;
+        s |= (flags.get(OPERATIONAL + 1) ? 1 : 0) << 1;
+        s |= (flags.get(OPERATIONAL) ? 1 : 0) << 2;
         builder.setOperational(OperationalStatus.forValue(s));
         final TlvsBuilder b = new TlvsBuilder();
         parseTlvs(b, bytes.slice());
@@ -117,25 +107,19 @@ public class Stateful07LspObjectParser extends AbstractObjectWithTlvsParser<Tlvs
         final ByteBuf body = Unpooled.buffer();
         Preconditions.checkArgument(specObj.getPlspId() != null, "PLSP-ID not present");
         writeMedium(specObj.getPlspId().getValue().intValue() << FOUR_BITS_SHIFT, body);
-        final BitSet flags = new BitSet(2 * Byte.SIZE);
-        if (specObj.isDelegate() != null) {
-            flags.set(DELEGATE_FLAG_OFFSET, specObj.isDelegate());
-        }
-        if (specObj.isRemove() != null) {
-            flags.set(REMOVE_FLAG_OFFSET, specObj.isRemove());
-        }
-        if (specObj.isSync() != null) {
-            flags.set(SYNC_FLAG_OFFSET, specObj.isSync());
-        }
-        if (specObj.isAdministrative() != null) {
-            flags.set(ADMINISTRATIVE_FLAG_OFFSET, specObj.isAdministrative());
-        }
+        final BitArray flags = new BitArray(FLAGS_SIZE);
+        flags.set(DELEGATE, specObj.isDelegate());
+        flags.set(REMOVE, specObj.isRemove());
+        flags.set(SYNC, specObj.isSync());
+        flags.set(ADMINISTRATIVE, specObj.isAdministrative());
         byte op = 0;
         if (specObj.getOperational() != null) {
             op = UnsignedBytes.checkedCast(specObj.getOperational().getIntValue());
             op = (byte) (op << FOUR_BITS_SHIFT);
         }
-        body.writeByte(ByteArray.bitSetToBytes(flags, 2)[1] | op);
+        final byte[] res = flags.array();
+        res[res.length -1] = (byte) (res[res.length -1] | op);
+        body.writeByte(res[res.length -1]);
         serializeTlvs(specObj.getTlvs(), body);
         ObjectUtil.formatSubobject(TYPE, CLASS, object.isProcessingRule(), object.isIgnore(), body, buffer);
     }
index 908ba1f2dfcb3418a27e29e177c1ecaaeb0a687d..4ec2d5f9f4dd48b1cf90ba1dc447b0f2bae33fe1 100644 (file)
@@ -7,7 +7,6 @@
  */
 package org.opendaylight.protocol.pcep.ietf.stateful07;
 
-import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeBitSet;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeIpv4Address;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeIpv6Address;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeUnsignedByte;
@@ -18,11 +17,11 @@ import com.google.common.base.Charsets;
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.TlvParser;
 import org.opendaylight.protocol.pcep.spi.TlvSerializer;
 import org.opendaylight.protocol.pcep.spi.TlvUtil;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.ByteArray;
 import org.opendaylight.protocol.util.Ipv4Util;
 import org.opendaylight.protocol.util.Ipv6Util;
@@ -49,7 +48,7 @@ public final class Stateful07RSVPErrorSpecTlvParser implements TlvParser, TlvSer
 
     public static final int TYPE = 21;
 
-    private static final int FLAGS_F_LENGTH = 1;
+    private static final int FLAGS_SIZE = 8;
     private static final int HEADER_LENGTH = 4;
 
     private static final int RSVP_ERROR_CLASS_NUM = 6;
@@ -59,8 +58,8 @@ public final class Stateful07RSVPErrorSpecTlvParser implements TlvParser, TlvSer
     private static final int USER_ERROR_CLASS_NUM = 194;
     private static final int USER_ERROR_CLASS_TYPE = 1;
 
-    private static final int IN_PLACE_FLAG_OFFSET = 7;
-    private static final int NOT_GUILTY_FLAGS_OFFSET = 6;
+    private static final int IN_PLACE = 7;
+    private static final int NOT_GUILTY = 6;
 
     @Override
     public RsvpErrorSpec parseTlv(final ByteBuf buffer) throws PCEPDeserializerException {
@@ -128,8 +127,8 @@ public final class Stateful07RSVPErrorSpecTlvParser implements TlvParser, TlvSer
         } else if (classType == RSVP_IPV6_ERROR_CLASS_TYPE) {
             builder.setNode(new IpAddress(Ipv6Util.addressForByteBuf(buffer)));
         }
-        final BitSet flags = ByteArray.bytesToBitSet(ByteArray.readBytes(buffer, FLAGS_F_LENGTH));
-        builder.setFlags(new Flags(flags.get(IN_PLACE_FLAG_OFFSET), flags.get(NOT_GUILTY_FLAGS_OFFSET)));
+        final BitArray flags = BitArray.valueOf(buffer, FLAGS_SIZE);
+        builder.setFlags(new Flags(flags.get(IN_PLACE), flags.get(NOT_GUILTY)));
         final short errorCode = buffer.readUnsignedByte();
         builder.setCode(errorCode);
         final int errorValue = buffer.readUnsignedShort();
@@ -138,9 +137,9 @@ public final class Stateful07RSVPErrorSpecTlvParser implements TlvParser, TlvSer
     }
 
     private void serializeRsvp(final RsvpError rsvp, final ByteBuf body) {
-        final BitSet flags = new BitSet(FLAGS_F_LENGTH * Byte.SIZE);
-        flags.set(IN_PLACE_FLAG_OFFSET, rsvp.getFlags().isInPlace());
-        flags.set(NOT_GUILTY_FLAGS_OFFSET, rsvp.getFlags().isNotGuilty());
+        final BitArray flags = new BitArray(FLAGS_SIZE);
+        flags.set(IN_PLACE, rsvp.getFlags().isInPlace());
+        flags.set(NOT_GUILTY, rsvp.getFlags().isNotGuilty());
         final IpAddress node = rsvp.getNode();
         Preconditions.checkArgument(node != null, "Node is mandatory.");
         final ByteBuf rsvpObjBuf = Unpooled.buffer();
@@ -152,7 +151,7 @@ public final class Stateful07RSVPErrorSpecTlvParser implements TlvParser, TlvSer
             type = RSVP_IPV6_ERROR_CLASS_TYPE;
             writeIpv6Address(node.getIpv6Address(), rsvpObjBuf);
         }
-        writeBitSet(flags, FLAGS_F_LENGTH, rsvpObjBuf);
+        flags.toByteBuf(rsvpObjBuf);
         Preconditions.checkArgument(rsvp.getCode() != null, "Code is mandatory.");
         writeUnsignedByte(rsvp.getCode(), rsvpObjBuf);
         Preconditions.checkArgument(rsvp.getValue() != null, "Value is mandatory.");
index 263c0fb0c6f60bf08a19268692e6680470637c91..184271776c8d6674c4deae87ef77a1ffd0a2bb19 100644 (file)
@@ -39,13 +39,11 @@ public class Stateful07SrpObjectParser extends AbstractObjectWithTlvsParser<Tlvs
 
     public static final int TYPE = 1;
 
-    protected static final int FLAGS_SIZE = 4;
+    protected static final int FLAGS_SIZE = 32;
 
     protected static final int SRP_ID_SIZE = 4;
 
-    protected static final int TLVS_OFFSET = FLAGS_SIZE + SRP_ID_SIZE;
-
-    protected static final int MIN_SIZE = FLAGS_SIZE + SRP_ID_SIZE;
+    protected static final int MIN_SIZE = FLAGS_SIZE / Byte.SIZE + SRP_ID_SIZE;
 
     protected Stateful07SrpObjectParser(final TlvRegistry tlvReg, final VendorInformationTlvRegistry viTlvReg) {
         super(tlvReg, viTlvReg);
@@ -61,7 +59,7 @@ public class Stateful07SrpObjectParser extends AbstractObjectWithTlvsParser<Tlvs
         final SrpBuilder builder = new SrpBuilder();
         builder.setIgnore(header.isIgnore());
         builder.setProcessingRule(header.isProcessingRule());
-        bytes.readerIndex(bytes.readerIndex() + FLAGS_SIZE);
+        bytes.skipBytes(FLAGS_SIZE / Byte.SIZE);
         builder.setOperationId(new SrpIdNumber(bytes.readUnsignedInt()));
         final TlvsBuilder tlvsBuilder = new TlvsBuilder();
         parseTlvs(tlvsBuilder, bytes.slice());
@@ -84,7 +82,7 @@ public class Stateful07SrpObjectParser extends AbstractObjectWithTlvsParser<Tlvs
         Preconditions.checkArgument(object instanceof Srp, "Wrong instance of PCEPObject. Passed %s . Needed SrpObject.", object.getClass());
         final Srp srp = (Srp) object;
         final ByteBuf body = Unpooled.buffer();
-        body.writerIndex(body.writerIndex() + FLAGS_SIZE);
+        body.writeZero(FLAGS_SIZE / Byte.SIZE);
         final SrpIdNumber srpId = srp.getOperationId();
         Preconditions.checkArgument(srpId != null, "SrpId is mandatory.");
         writeUnsignedInt(srpId.getValue(), body);
index ecddf39e2423674fc1a978fcfbe52dffd0a0e545..ba863fbedc55f6cb3ec282d3daec33683a30201e 100644 (file)
@@ -7,17 +7,14 @@
  */
 package org.opendaylight.protocol.pcep.ietf.stateful07;
 
-import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeBitSet;
-
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.TlvParser;
 import org.opendaylight.protocol.pcep.spi.TlvSerializer;
 import org.opendaylight.protocol.pcep.spi.TlvUtil;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.stateful.capability.tlv.Stateful;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.stateful.capability.tlv.StatefulBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Tlv;
@@ -29,7 +26,7 @@ public class Stateful07StatefulCapabilityTlvParser implements TlvParser, TlvSeri
 
     public static final int TYPE = 16;
 
-    protected static final int FLAGS_F_LENGTH = 4;
+    protected static final int FLAGS_F_LENGTH = 32;
 
     protected static final int U_FLAG_OFFSET = 31;
 
@@ -38,12 +35,11 @@ public class Stateful07StatefulCapabilityTlvParser implements TlvParser, TlvSeri
         if (buffer == null) {
             return null;
         }
-        if (buffer.readableBytes() < FLAGS_F_LENGTH) {
+        if (buffer.readableBytes() < FLAGS_F_LENGTH / Byte.SIZE) {
             throw new PCEPDeserializerException("Wrong length of array of bytes. Passed: " + buffer.readableBytes() + "; Expected: >= "
-                    + FLAGS_F_LENGTH + ".");
+                    + FLAGS_F_LENGTH / Byte.SIZE + ".");
         }
-        final BitSet flags = ByteArray.bytesToBitSet(ByteArray.readBytes(buffer, FLAGS_F_LENGTH));
-
+        final BitArray flags = BitArray.valueOf(buffer, FLAGS_F_LENGTH);
         final StatefulBuilder sb = new StatefulBuilder();
         sb.setLspUpdateCapability(flags.get(U_FLAG_OFFSET));
         return sb.build();
@@ -53,12 +49,8 @@ public class Stateful07StatefulCapabilityTlvParser implements TlvParser, TlvSeri
     public void serializeTlv(final Tlv tlv, final ByteBuf buffer) {
         Preconditions.checkArgument(tlv instanceof Stateful, "StatefulCapabilityTlv is mandatory.");
         final Stateful sct = (Stateful) tlv;
-        final ByteBuf body = Unpooled.buffer();
-        final BitSet flags = new BitSet(FLAGS_F_LENGTH * Byte.SIZE);
-        if (sct.isLspUpdateCapability() != null) {
-            flags.set(U_FLAG_OFFSET, sct.isLspUpdateCapability());
-        }
-        writeBitSet(flags, FLAGS_F_LENGTH, body);
-        TlvUtil.formatTlv(TYPE, body, buffer);
+        final BitArray flags = new BitArray(FLAGS_F_LENGTH);
+        flags.set(U_FLAG_OFFSET, sct.isLspUpdateCapability());
+        TlvUtil.formatTlv(TYPE, Unpooled.wrappedBuffer(flags.array()), buffer);
     }
 }
index ce4d9f56d64ec450f87834dadabfddc22fa1b695..0abe24da5b76af4b394060306c37216c4905fc86 100644 (file)
@@ -230,7 +230,7 @@ public class PCEPObjectParserTest {
             /* pst-tlv */
             0x0, 0x1C, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0 };
         final CInitiated00SrpObjectParser parser = new CInitiated00SrpObjectParser(this.tlvRegistry, this.viTlvRegistry);
-        SrpBuilder builder = new SrpBuilder();
+        final SrpBuilder builder = new SrpBuilder();
         builder.setProcessingRule(false);
         builder.setIgnore(false);
         builder.setOperationId(new SrpIdNumber(1L));
index a545aafa5a8c3af3c24db6b96ac2071a6fa3598e..1060db9e055fad480fee9ca1aeb7af647efc9132 100644 (file)
@@ -62,7 +62,7 @@ public final class PCEPByteToMessageDecoder extends ByteToMessageDecoder {
     }
 
     private Message parse(final ByteBuf buffer, final List<Message> errors) throws PCEPDeserializerException {
-        buffer.readerIndex(buffer.readerIndex() + 1);
+        buffer.skipBytes(1);
         final int type = buffer.readUnsignedByte();
         final int msgLength = buffer.readUnsignedShort();
         final int actualLength = buffer.readableBytes();
@@ -71,7 +71,7 @@ public final class PCEPByteToMessageDecoder extends ByteToMessageDecoder {
             throw new PCEPDeserializerException("Body size " + actualLength + " does not match header size "
                     + (msgLength - PCEPMessageConstants.COMMON_HEADER_LENGTH));
         }
-        buffer.readerIndex(buffer.readerIndex() + actualLength);
+        buffer.skipBytes(actualLength);
         return this.registry.parseMessage(type, msgBody, errors);
     }
 }
index 135641960e4d53079c0467bc1d4ae86246b3dd83..33ebb968f421bfe2d1dcc34ff6bc0379eb764dde 100644 (file)
@@ -52,7 +52,7 @@ public class PCEPCloseObjectParser extends AbstractObjectWithTlvsParser<TlvsBuil
         final CCloseBuilder builder = new CCloseBuilder();
         builder.setIgnore(header.isIgnore());
         builder.setProcessingRule(header.isProcessingRule());
-        bytes.readerIndex(bytes.readerIndex() + FLAGS_F_LENGTH + RESERVED);
+        bytes.skipBytes(FLAGS_F_LENGTH + RESERVED);
         builder.setReason(bytes.readUnsignedByte());
         final TlvsBuilder tlvsBuilder = new TlvsBuilder();
         parseTlvs(tlvsBuilder, bytes.slice());
index 5533e796a2bdcac4cf036343805c8c99f77dd7bb..c960edf7d9feab3182772d69377cda20b3d0b9dc 100644 (file)
@@ -52,7 +52,7 @@ public class PCEPErrorObjectParser extends AbstractObjectWithTlvsParser<ErrorObj
         final ErrorObjectBuilder builder = new ErrorObjectBuilder();
         builder.setIgnore(header.isIgnore());
         builder.setProcessingRule(header.isProcessingRule());
-        bytes.readerIndex(bytes.readerIndex() + FLAGS_F_LENGTH + RESERVED);
+        bytes.skipBytes(FLAGS_F_LENGTH + RESERVED);
         builder.setType(bytes.readUnsignedByte());
         builder.setValue(bytes.readUnsignedByte());
         parseTlvs(builder, bytes.slice());
index 0685b7bc92e589bedadd7f2dce1387de8452a5f4..2e409f3860228512e06126780b6d2b42d73ffe46 100644 (file)
@@ -42,7 +42,7 @@ public final class PCEPExcludeRouteObjectParser extends AbstractXROWithSubobject
         final XroBuilder builder = new XroBuilder();
         builder.setIgnore(header.isIgnore());
         builder.setProcessingRule(header.isProcessingRule());
-        bytes.readerIndex(bytes.readerIndex() + FLAGS_OFFSET);
+        bytes.skipBytes(FLAGS_OFFSET);
         builder.setFlags(new Flags(bytes.readBoolean()));
         builder.setSubobject(parseSubobjects(bytes.slice()));
         return builder.build();
index 773d219323e3bbb7ecbb62be0f256a4d0272835e..c035a56156cf379fc4a6159446999efd9a08f1fa 100644 (file)
@@ -48,7 +48,7 @@ public class PCEPLoadBalancingObjectParser implements ObjectParser, ObjectSerial
         final LoadBalancingBuilder builder = new LoadBalancingBuilder();
         builder.setIgnore(header.isIgnore());
         builder.setProcessingRule(header.isProcessingRule());
-        bytes.readerIndex(bytes.readerIndex() + RESERVED + FLAGS_F_LENGTH);
+        bytes.skipBytes(RESERVED + FLAGS_F_LENGTH);
         builder.setMaxLsp(bytes.readUnsignedByte());
         builder.setMinBandwidth(new Bandwidth(ByteArray.readAllBytes(bytes)));
         return builder.build();
index c69d8db8ed408a93bdc221fc84228078fd6684d2..6975d56d771d76f5a4ca8d557d33f3f07ec618d3 100644 (file)
@@ -7,21 +7,19 @@
  */
 package org.opendaylight.protocol.pcep.impl.object;
 
-import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeBitSet;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeUnsignedByte;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeUnsignedInt;
 
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import java.util.List;
 import org.opendaylight.protocol.pcep.spi.AbstractObjectWithTlvsParser;
 import org.opendaylight.protocol.pcep.spi.ObjectUtil;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.TlvRegistry;
 import org.opendaylight.protocol.pcep.spi.VendorInformationTlvRegistry;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Object;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.ObjectHeader;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.lspa.object.Lspa;
@@ -43,7 +41,7 @@ public class PCEPLspaObjectParser extends AbstractObjectWithTlvsParser<TlvsBuild
     /*
      * lengths of fields in bytes
      */
-    private static final int FLAGS_F_LENGTH = 1;
+    private static final int FLAGS_SIZE = 8;
 
     /*
      * offsets of flags inside flags field in bits
@@ -69,10 +67,10 @@ public class PCEPLspaObjectParser extends AbstractObjectWithTlvsParser<TlvsBuild
         builder.setSetupPriority(bytes.readUnsignedByte());
         builder.setHoldPriority(bytes.readUnsignedByte());
 
-        final BitSet flags = ByteArray.bytesToBitSet(new byte[] { bytes.readByte() });
+        final BitArray flags = BitArray.valueOf(bytes.readByte());
         builder.setLocalProtectionDesired(flags.get(L_FLAG_OFFSET));
         final TlvsBuilder tbuilder = new TlvsBuilder();
-        bytes.readerIndex(bytes.readerIndex() + RESERVED);
+        bytes.skipBytes(RESERVED);
         parseTlvs(tbuilder, bytes.slice());
         builder.setTlvs(tbuilder.build());
         return builder.build();
@@ -88,11 +86,9 @@ public class PCEPLspaObjectParser extends AbstractObjectWithTlvsParser<TlvsBuild
         writeAttributeFilter(lspaObj.getIncludeAll(), body);
         writeUnsignedByte(lspaObj.getSetupPriority(), body);
         writeUnsignedByte(lspaObj.getHoldPriority(), body);
-        final BitSet flags = new BitSet(FLAGS_F_LENGTH * Byte.SIZE);
-        if (lspaObj.isLocalProtectionDesired() != null) {
-            flags.set(L_FLAG_OFFSET, lspaObj.isLocalProtectionDesired());
-        }
-        writeBitSet(flags, FLAGS_F_LENGTH, body);
+        final BitArray flags = new BitArray(FLAGS_SIZE);
+        flags.set(L_FLAG_OFFSET, lspaObj.isLocalProtectionDesired());
+        flags.toByteBuf(body);
         body.writeZero(RESERVED);
         serializeTlvs(lspaObj.getTlvs(), body);
         ObjectUtil.formatSubobject(TYPE, CLASS, object.isProcessingRule(), object.isIgnore(), body, buffer);
index 57cd412b1159ac5eefe50d3fea2288cba567ee02..33bd86b612b6b874a179726be774eb3c1c0615de 100644 (file)
@@ -7,18 +7,17 @@
  */
 package org.opendaylight.protocol.pcep.impl.object;
 
-import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeBitSet;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeFloat32;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeUnsignedByte;
 
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.spi.ObjectParser;
 import org.opendaylight.protocol.pcep.spi.ObjectSerializer;
 import org.opendaylight.protocol.pcep.spi.ObjectUtil;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.ByteArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ieee754.rev130819.Float32;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Object;
@@ -38,7 +37,7 @@ public class PCEPMetricObjectParser implements ObjectParser, ObjectSerializer {
     /*
      * lengths of fields in bytes
      */
-    private static final int FLAGS_F_LENGTH = 1;
+    private static final int FLAGS_SIZE = 8;
     private static final int METRIC_VALUE_F_LENGTH = 4;
 
     /*
@@ -61,9 +60,8 @@ public class PCEPMetricObjectParser implements ObjectParser, ObjectSerializer {
             throw new PCEPDeserializerException("Wrong length of array of bytes. Passed: " + bytes.readableBytes() + "; Expected: " + SIZE
                     + ".");
         }
-        bytes.readerIndex(bytes.readerIndex() + RESERVED);
-        final byte[] flagBytes = { bytes.readByte() };
-        final BitSet flags = ByteArray.bytesToBitSet(flagBytes);
+        bytes.skipBytes(RESERVED);
+        final BitArray flags = BitArray.valueOf(bytes.readByte());
         final MetricBuilder builder = new MetricBuilder();
         builder.setIgnore(header.isIgnore());
         builder.setProcessingRule(header.isProcessingRule());
@@ -80,14 +78,10 @@ public class PCEPMetricObjectParser implements ObjectParser, ObjectSerializer {
         final Metric mObj = (Metric) object;
         final ByteBuf body = Unpooled.buffer(SIZE);
         body.writeZero(RESERVED);
-        final BitSet flags = new BitSet(FLAGS_F_LENGTH * Byte.SIZE);
-        if (mObj.isComputed() != null) {
-            flags.set(C_FLAG_OFFSET, mObj.isComputed());
-        }
-        if (mObj.isBound() != null) {
-            flags.set(B_FLAG_OFFSET, mObj.isBound());
-        }
-        writeBitSet(flags, FLAGS_F_LENGTH, body);
+        final BitArray flags = new BitArray(FLAGS_SIZE);
+        flags.set(C_FLAG_OFFSET, mObj.isComputed());
+        flags.set(B_FLAG_OFFSET, mObj.isBound());
+        flags.toByteBuf(body);
         Preconditions.checkArgument(mObj.getMetricType() != null, "MetricType is mandatory.");
         writeUnsignedByte(mObj.getMetricType(), body);
         writeFloat32(mObj.getValue(), body);
index efd734ed03d06ba7e13b3e12de527ab0d128f6da..487f6622a990966c7d9997e4cba00aaef3d3a2b8 100644 (file)
@@ -11,14 +11,13 @@ package org.opendaylight.protocol.pcep.impl.object;
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import java.util.List;
 import org.opendaylight.protocol.pcep.spi.AbstractObjectWithTlvsParser;
 import org.opendaylight.protocol.pcep.spi.ObjectUtil;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.TlvRegistry;
 import org.opendaylight.protocol.pcep.spi.VendorInformationTlvRegistry;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.ByteBufWriteUtil;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Object;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.ObjectHeader;
@@ -39,7 +38,7 @@ public class PCEPMonitoringObjectParser extends AbstractObjectWithTlvsParser<Tlv
 
     public static final int TYPE = 1;
 
-    private static final int FLAGS = 3;
+    private static final int FLAGS_SIZE = 24;
     private static final int RESERVED = 1;
     private static final int L_FLAG_POS = 23;
     private static final int G_FLAG_POS = 22;
@@ -56,7 +55,7 @@ public class PCEPMonitoringObjectParser extends AbstractObjectWithTlvsParser<Tlv
         Preconditions.checkArgument(buffer != null && buffer.isReadable(), "Array of bytes is mandatory. Can't be null or empty.");
         final MonitoringBuilder builder = new MonitoringBuilder();
         buffer.readBytes(RESERVED);
-        final BitSet flagBits = ByteArray.bytesToBitSet(buffer.readBytes(FLAGS).array());
+        final BitArray flagBits = BitArray.valueOf(buffer, FLAGS_SIZE);
         final Flags flags = new Flags(flagBits.get(G_FLAG_POS), flagBits.get(I_FLAG_POS), flagBits.get(L_FLAG_POS),
                 flagBits.get(C_FLAG_POS), flagBits.get(P_FLAG_POS));
         builder.setFlags(flags);
@@ -74,13 +73,13 @@ public class PCEPMonitoringObjectParser extends AbstractObjectWithTlvsParser<Tlv
         final ByteBuf body = Unpooled.buffer();
         body.writeZero(RESERVED);
         final Flags flags = monitoring.getFlags();
-        final BitSet flagBits = new BitSet(FLAGS);
+        final BitArray flagBits = new BitArray(FLAGS_SIZE);
         flagBits.set(I_FLAG_POS, flags.isIncomplete());
         flagBits.set(C_FLAG_POS, flags.isOverload());
         flagBits.set(P_FLAG_POS, flags.isProcessingTime());
         flagBits.set(G_FLAG_POS, flags.isGeneral());
         flagBits.set(L_FLAG_POS, flags.isLiveness());
-        ByteBufWriteUtil.writeBitSet(flagBits, FLAGS, body);
+        flagBits.toByteBuf(body);
         ByteBufWriteUtil.writeUnsignedInt(monitoring.getMonitoringId(), body);
         serializeTlvs(monitoring.getTlvs(), body);
         ObjectUtil.formatSubobject(TYPE, CLASS, object.isProcessingRule(), object.isIgnore(), body, buffer);
index 91e4bdddd3a7b17efe27fcc33b202e2e3052d915..8df98be321c4ed0e1d07d35c8027a24bf6be0ba8 100644 (file)
@@ -7,20 +7,18 @@
  */
 package org.opendaylight.protocol.pcep.impl.object;
 
-import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeBitSet;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeUnsignedByte;
 
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import java.util.List;
 import org.opendaylight.protocol.pcep.spi.AbstractObjectWithTlvsParser;
 import org.opendaylight.protocol.pcep.spi.ObjectUtil;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.TlvRegistry;
 import org.opendaylight.protocol.pcep.spi.VendorInformationTlvRegistry;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Object;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.ObjectHeader;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Tlv;
@@ -43,7 +41,7 @@ public class PCEPNoPathObjectParser extends AbstractObjectWithTlvsParser<TlvsBui
     /*
      * lengths of fields in bytes
      */
-    private static final int FLAGS_F_LENGTH = 2;
+    private static final int FLAGS_SIZE = 16;
     private static final int RESERVED_F_LENGTH = 1;
 
     /*
@@ -63,10 +61,9 @@ public class PCEPNoPathObjectParser extends AbstractObjectWithTlvsParser<TlvsBui
         builder.setProcessingRule(header.isProcessingRule());
 
         builder.setNatureOfIssue(bytes.readUnsignedByte());
-        final byte[] flagsByte = ByteArray.readBytes(bytes, FLAGS_F_LENGTH);
-        final BitSet flags = ByteArray.bytesToBitSet(flagsByte);
+        final BitArray flags = BitArray.valueOf(bytes, FLAGS_SIZE);
         builder.setUnsatisfiedConstraints(flags.get(C_FLAG_OFFSET));
-        bytes.readerIndex(bytes.readerIndex() + RESERVED_F_LENGTH);
+        bytes.skipBytes(RESERVED_F_LENGTH);
         final TlvsBuilder tlvsBuilder = new TlvsBuilder();
         parseTlvs(tlvsBuilder, bytes.slice());
         builder.setTlvs(tlvsBuilder.build());
@@ -87,11 +84,9 @@ public class PCEPNoPathObjectParser extends AbstractObjectWithTlvsParser<TlvsBui
         final ByteBuf body = Unpooled.buffer();
         Preconditions.checkArgument(nPObj.getNatureOfIssue() != null, "NatureOfIssue is mandatory.");
         writeUnsignedByte(nPObj.getNatureOfIssue(), body);
-        final BitSet flags = new BitSet(FLAGS_F_LENGTH * Byte.SIZE);
-        if (nPObj.isUnsatisfiedConstraints() != null) {
-            flags.set(C_FLAG_OFFSET, nPObj.isUnsatisfiedConstraints());
-        }
-        writeBitSet(flags, FLAGS_F_LENGTH, body);
+        final BitArray flags = new BitArray(FLAGS_SIZE);
+        flags.set(C_FLAG_OFFSET, nPObj.isUnsatisfiedConstraints());
+        flags.toByteBuf(body);
         body.writeZero(RESERVED_F_LENGTH);
         serializeTlvs(nPObj.getTlvs(), body);
         ObjectUtil.formatSubobject(TYPE, CLASS, object.isProcessingRule(), object.isIgnore(), body, buffer);
index 82d0b22628f385b16727b173a0f4a36c1fe5b64c..bf095a438e83a1e338e755f5871a32b66409892c 100644 (file)
@@ -52,7 +52,7 @@ public class PCEPNotificationObjectParser extends AbstractObjectWithTlvsParser<C
         final CNotificationBuilder builder = new CNotificationBuilder();
         builder.setIgnore(header.isIgnore());
         builder.setProcessingRule(header.isProcessingRule());
-        bytes.readerIndex(bytes.readerIndex() + NT_F_OFFSET);
+        bytes.skipBytes(NT_F_OFFSET);
         builder.setType(bytes.readUnsignedByte());
         builder.setValue(bytes.readUnsignedByte());
         parseTlvs(builder, bytes.slice());
index a9b6e0af06b5351d36d4a07f964bf95a48b6f609..65678023d1454f94c37b98dd50de77227c9180da 100644 (file)
@@ -5,7 +5,6 @@
  * 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.pcep.impl.object;
 
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.INT_BYTES_LENGTH;
@@ -13,12 +12,11 @@ import static org.opendaylight.protocol.util.ByteBufWriteUtil.INT_BYTES_LENGTH;
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.spi.ObjectParser;
 import org.opendaylight.protocol.pcep.spi.ObjectSerializer;
 import org.opendaylight.protocol.pcep.spi.ObjectUtil;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.ByteBufWriteUtil;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Object;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.ObjectHeader;
@@ -36,7 +34,7 @@ public class PCEPProcTimeObjectParser implements ObjectParser, ObjectSerializer
     public static final int TYPE = 1;
 
     private static final int RESERVED = 2;
-    private static final int FLAGS = RESERVED;
+    private static final int FLAGS = 16;
     private static final int COUNT_FIELDS = 5;
     private static final int BODY_SIZE = RESERVED + FLAGS + COUNT_FIELDS * INT_BYTES_LENGTH;
     private static final int E_FLAG_POSITION = 15;
@@ -47,9 +45,9 @@ public class PCEPProcTimeObjectParser implements ObjectParser, ObjectSerializer
         final ProcTime procTime = (ProcTime) object;
         final ByteBuf body = Unpooled.buffer(BODY_SIZE);
         body.writeZero(RESERVED);
-        final BitSet flagBits = new BitSet(FLAGS * Byte.SIZE);
+        final BitArray flagBits = new BitArray(FLAGS);
         flagBits.set(E_FLAG_POSITION, procTime.isEstimated());
-        ByteBufWriteUtil.writeBitSet(flagBits, FLAGS, body);
+        flagBits.toByteBuf(body);
         ByteBufWriteUtil.writeUnsignedInt(procTime.getCurrentProcTime(), body);
         ByteBufWriteUtil.writeUnsignedInt(procTime.getMinProcTime(), body);
         ByteBufWriteUtil.writeUnsignedInt(procTime.getMaxProcTime(), body);
@@ -62,8 +60,8 @@ public class PCEPProcTimeObjectParser implements ObjectParser, ObjectSerializer
     public Object parseObject(final ObjectHeader header, final ByteBuf buffer) throws PCEPDeserializerException {
         Preconditions.checkArgument(buffer != null && buffer.isReadable(), "Array of bytes is mandatory. Can't be null or empty.");
         final ProcTimeBuilder builder = new ProcTimeBuilder();
-        buffer.readBytes(RESERVED);
-        final BitSet flagBits = ByteArray.bytesToBitSet(buffer.readBytes(FLAGS).array());
+        buffer.skipBytes(RESERVED);
+        final BitArray flagBits = BitArray.valueOf(buffer, FLAGS);
         builder.setEstimated(flagBits.get(E_FLAG_POSITION));
         builder.setCurrentProcTime(buffer.readUnsignedInt());
         builder.setMinProcTime(buffer.readUnsignedInt());
index 83c0544ca06462b3df8e84bc760f6ecc91b30492..b9fc394d8dc438ffd910b462d7ceae9f3bdbbf1e 100644 (file)
@@ -8,21 +8,19 @@
 
 package org.opendaylight.protocol.pcep.impl.object;
 
-import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeBitSet;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeUnsignedInt;
 
 import com.google.common.base.Preconditions;
 import com.google.common.primitives.UnsignedBytes;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import java.util.List;
 import org.opendaylight.protocol.pcep.spi.AbstractObjectWithTlvsParser;
 import org.opendaylight.protocol.pcep.spi.ObjectUtil;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.TlvRegistry;
 import org.opendaylight.protocol.pcep.spi.VendorInformationTlvRegistry;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Object;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.ObjectHeader;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.RequestId;
@@ -47,7 +45,7 @@ public class PCEPRequestParameterObjectParser extends AbstractObjectWithTlvsPars
     /*
      * lengths of fields in bytes
      */
-    private static final int FLAGS_PRI_MF_LENGTH = 4;
+    private static final int FLAGS_SIZE = 32;
 
     /*
      * lengths of subfields inside multi-field in bits
@@ -99,7 +97,7 @@ public class PCEPRequestParameterObjectParser extends AbstractObjectWithTlvsPars
     @Override
     public Object parseObject(final ObjectHeader header, final ByteBuf bytes) throws PCEPDeserializerException {
         Preconditions.checkArgument(bytes != null && bytes.isReadable(), "Array of bytes is mandatory. Can't be null or empty.");
-        final BitSet flags = ByteArray.bytesToBitSet(ByteArray.readBytes(bytes, FLAGS_PRI_MF_LENGTH));
+        final BitArray flags = BitArray.valueOf(bytes, FLAGS_SIZE);
 
         final RpBuilder builder = new RpBuilder();
         builder.setIgnore(header.isIgnore());
@@ -143,42 +141,23 @@ public class PCEPRequestParameterObjectParser extends AbstractObjectWithTlvsPars
         Preconditions.checkArgument(object instanceof Rp, "Wrong instance of PCEPObject. Passed %s. Needed RPObject.", object.getClass());
         final ByteBuf body = Unpooled.buffer();
         final Rp rpObj = (Rp) object;
-        final BitSet flags = new BitSet(FLAGS_PRI_MF_LENGTH * Byte.SIZE);
-        if (rpObj.isReoptimization() != null) {
-            flags.set(R_FLAG_OFFSET, rpObj.isReoptimization());
-        }
-        if (rpObj.isBiDirectional() != null) {
-            flags.set(B_FLAG_OFFSET, rpObj.isBiDirectional());
-        }
-        if (rpObj.isLoose() != null) {
-            flags.set(O_FLAG_OFFSET, rpObj.isLoose());
-        }
-        if (rpObj.isMakeBeforeBreak() != null) {
-            flags.set(M_FLAG_OFFSET, rpObj.isMakeBeforeBreak());
-        }
-        if (rpObj.isOrder() != null) {
-            flags.set(D_FLAG_OFFSET, rpObj.isOrder());
-        }
-        if (rpObj.isPathKey() != null) {
-            flags.set(P_FLAG_OFFSET, rpObj.isPathKey());
-        }
-        if (rpObj.isSupplyOf() != null) {
-            flags.set(S_FLAG_OFFSET, rpObj.isSupplyOf());
-        }
-        if (rpObj.isFragmentation() != null) {
-            flags.set(F_FLAG_OFFSET, rpObj.isFragmentation());
-        }
-        if (rpObj.isP2mp() != null) {
-            flags.set(N_FLAG_OFFSET, rpObj.isP2mp());
-        }
-        if (rpObj.isEroCompression() != null) {
-            flags.set(E_FLAG_OFFSET, rpObj.isEroCompression());
-        }
+        final BitArray flags = new BitArray(FLAGS_SIZE);
+        flags.set(R_FLAG_OFFSET, rpObj.isReoptimization());
+        flags.set(B_FLAG_OFFSET, rpObj.isBiDirectional());
+        flags.set(O_FLAG_OFFSET, rpObj.isLoose());
+        flags.set(M_FLAG_OFFSET, rpObj.isMakeBeforeBreak());
+        flags.set(D_FLAG_OFFSET, rpObj.isOrder());
+        flags.set(P_FLAG_OFFSET, rpObj.isPathKey());
+        flags.set(S_FLAG_OFFSET, rpObj.isSupplyOf());
+        flags.set(F_FLAG_OFFSET, rpObj.isFragmentation());
+        flags.set(N_FLAG_OFFSET, rpObj.isP2mp());
+        flags.set(E_FLAG_OFFSET, rpObj.isEroCompression());
+        final byte[] res = flags.array();
         if (rpObj.getPriority() != null) {
-            final byte[] p = { 0, 0, 0, UnsignedBytes.checkedCast(rpObj.getPriority().shortValue())};
-            flags.or(ByteArray.bytesToBitSet(p));
+            final byte p = UnsignedBytes.checkedCast(rpObj.getPriority().shortValue());
+            res[res.length -1] = (byte) (res[res.length -1] | p);
         }
-        writeBitSet(flags, FLAGS_PRI_MF_LENGTH, body);
+        body.writeBytes(res);
         Preconditions.checkArgument(rpObj.getRequestId() != null, "RequestId is mandatory");
         writeUnsignedInt(rpObj.getRequestId().getValue(), body);
         serializeTlvs(rpObj.getTlvs(), body);
index 3cf8f593f0bada13b2fd6467f99d9dc21e095162..2512d00c57ef5d1a8bab2bff002a24702f4e1ec5 100644 (file)
@@ -7,20 +7,18 @@
  */
 package org.opendaylight.protocol.pcep.impl.object;
 
-import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeBitSet;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeUnsignedInt;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import java.util.List;
 import org.opendaylight.protocol.pcep.spi.ObjectParser;
 import org.opendaylight.protocol.pcep.spi.ObjectSerializer;
 import org.opendaylight.protocol.pcep.spi.ObjectUtil;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Object;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.ObjectHeader;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.RequestId;
@@ -39,7 +37,7 @@ public class PCEPSvecObjectParser implements ObjectParser, ObjectSerializer {
     /*
      * field lengths in bytes
      */
-    private static final int FLAGS_F_LENGTH = 3;
+    private static final int FLAGS_SIZE = 24;
 
     /*
      * fields offsets in bytes
@@ -56,7 +54,7 @@ public class PCEPSvecObjectParser implements ObjectParser, ObjectSerializer {
     /*
      * min size in bytes
      */
-    private static final int MIN_SIZE = FLAGS_F_LENGTH + FLAGS_F_OFFSET;
+    private static final int MIN_SIZE = FLAGS_SIZE / Byte.SIZE + FLAGS_F_OFFSET;
 
     @Override
     public Svec parseObject(final ObjectHeader header, final ByteBuf bytes) throws PCEPDeserializerException {
@@ -65,8 +63,8 @@ public class PCEPSvecObjectParser implements ObjectParser, ObjectSerializer {
             throw new PCEPDeserializerException("Wrong length of array of bytes. Passed: " + bytes.readableBytes() + "; Expected: >="
                     + MIN_SIZE + ".");
         }
-        bytes.readerIndex(bytes.readerIndex() + FLAGS_F_OFFSET);
-        final BitSet flags = ByteArray.bytesToBitSet(ByteArray.readBytes(bytes, FLAGS_F_LENGTH));
+        bytes.skipBytes(FLAGS_F_OFFSET);
+        final BitArray flags = BitArray.valueOf(bytes, FLAGS_SIZE);
         final List<RequestId> requestIDs = Lists.newArrayList();
 
         while (bytes.isReadable()) {
@@ -93,17 +91,11 @@ public class PCEPSvecObjectParser implements ObjectParser, ObjectSerializer {
         final Svec svecObj = (Svec) object;
         final ByteBuf body = Unpooled.buffer();
         body.writeZero(FLAGS_F_OFFSET);
-        final BitSet flags = new BitSet(FLAGS_F_LENGTH * Byte.SIZE);
-        if (svecObj.isLinkDiverse() != null) {
-            flags.set(L_FLAG_OFFSET, svecObj.isLinkDiverse());
-        }
-        if (svecObj.isNodeDiverse() != null) {
-            flags.set(N_FLAG_OFFSET, svecObj.isNodeDiverse());
-        }
-        if (svecObj.isSrlgDiverse() != null) {
-            flags.set(S_FLAG_OFFSET, svecObj.isSrlgDiverse());
-        }
-        writeBitSet(flags, FLAGS_F_LENGTH, body);
+        final BitArray flags = new BitArray(FLAGS_SIZE);
+        flags.set(L_FLAG_OFFSET, svecObj.isLinkDiverse());
+        flags.set(N_FLAG_OFFSET, svecObj.isNodeDiverse());
+        flags.set(S_FLAG_OFFSET, svecObj.isSrlgDiverse());
+        flags.toByteBuf(body);
 
         final List<RequestId> requestIDs = svecObj.getRequestsIds();
         assert !(requestIDs.isEmpty()) : "Empty Svec Object - no request ids.";
index f6344ec633a7a336b232cf3de167af1a02543d88..b772daf5dabcb4650df19b999112a8dd01729169 100644 (file)
@@ -10,13 +10,12 @@ package org.opendaylight.protocol.pcep.impl.subobject;
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.spi.EROSubobjectParser;
 import org.opendaylight.protocol.pcep.spi.EROSubobjectSerializer;
 import org.opendaylight.protocol.pcep.spi.EROSubobjectUtil;
 import org.opendaylight.protocol.pcep.spi.LabelRegistry;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.explicit.route.object.ero.Subobject;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.explicit.route.object.ero.SubobjectBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev130820.basic.explicit.route.subobjects.subobject.type.LabelCase;
@@ -29,13 +28,11 @@ public class EROLabelSubobjectParser implements EROSubobjectParser, EROSubobject
 
     public static final int TYPE = 3;
 
-    private static final int RES_F_LENGTH = 1;
+    private static final int FLAGS_SIZE = 8;
 
     private static final int C_TYPE_F_LENGTH = 1;
 
-    private static final int RES_F_OFFSET = 0;
-
-    private static final int C_TYPE_F_OFFSET = RES_F_OFFSET + RES_F_LENGTH;
+    private static final int C_TYPE_F_OFFSET = FLAGS_SIZE / Byte.SIZE;
 
     private static final int HEADER_LENGTH = C_TYPE_F_OFFSET + C_TYPE_F_LENGTH;
 
@@ -54,7 +51,7 @@ public class EROLabelSubobjectParser implements EROSubobjectParser, EROSubobject
             throw new PCEPDeserializerException("Wrong length of array of bytes. Passed: " + buffer.readableBytes() + "; Expected: >"
                     + HEADER_LENGTH + ".");
         }
-        final BitSet reserved = ByteArray.bytesToBitSet(ByteArray.readBytes(buffer, RES_F_LENGTH));
+        final BitArray reserved = BitArray.valueOf(buffer, FLAGS_SIZE);
         final short cType = buffer.readUnsignedByte();
 
         final LabelType labelType = this.registry.parseLabel(cType, buffer.slice());
index a7656df90d86900a4d1ad179c2f65f1e88f32589..3bfda2222717509b69a40bbda7fb89d48d1085b8 100644 (file)
@@ -44,7 +44,7 @@ public class EROUnnumberedInterfaceSubobjectParser implements EROSubobjectParser
         final SubobjectBuilder builder = new SubobjectBuilder();
         builder.setLoose(loose);
         final UnnumberedBuilder ubuilder = new UnnumberedBuilder();
-        buffer.readerIndex(buffer.readerIndex() + RESERVED);
+        buffer.skipBytes(RESERVED);
         ubuilder.setRouterId(buffer.readUnsignedInt());
         ubuilder.setInterfaceId(buffer.readUnsignedInt());
         builder.setSubobjectType(new UnnumberedCaseBuilder().setUnnumbered(ubuilder.build()).build());
index 2fd8c0167b9c58637dcd1d50e2e3d3395ead6311..85ecd63e0831569a6e30f7d38224e460612153a4 100644 (file)
@@ -7,17 +7,16 @@
  */
 package org.opendaylight.protocol.pcep.impl.subobject;
 
-import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeBitSet;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeIpv4Prefix;
 
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.RROSubobjectParser;
 import org.opendaylight.protocol.pcep.spi.RROSubobjectSerializer;
 import org.opendaylight.protocol.pcep.spi.RROSubobjectUtil;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.ByteArray;
 import org.opendaylight.protocol.util.Ipv4Util;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
@@ -36,11 +35,11 @@ public class RROIpv4PrefixSubobjectParser implements RROSubobjectParser, RROSubo
     public static final int TYPE = 1;
 
     private static final int PREFIX_F_LENGTH = 1;
-    private static final int FLAGS_F_LENGTH = 1;
+    private static final int FLAGS_SIZE = 8;
 
     private static final int PREFIX4_F_OFFSET = 0 + Ipv4Util.IP4_LENGTH;
 
-    private static final int CONTENT4_LENGTH = Ipv4Util.IP4_LENGTH + PREFIX_F_LENGTH + FLAGS_F_LENGTH;
+    private static final int CONTENT4_LENGTH = Ipv4Util.IP4_LENGTH + PREFIX_F_LENGTH + FLAGS_SIZE / Byte.SIZE;
 
     private static final int LPA_F_OFFSET = 7;
     private static final int LPIU_F_OFFSET = 6;
@@ -55,8 +54,8 @@ public class RROIpv4PrefixSubobjectParser implements RROSubobjectParser, RROSubo
         final int length = buffer.getUnsignedByte(PREFIX4_F_OFFSET);
         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev130820.record.route.subobjects.subobject.type.ip.prefix._case.IpPrefix prefix = new IpPrefixBuilder().setIpPrefix(
                 new IpPrefix(Ipv4Util.prefixForBytes(ByteArray.readBytes(buffer, Ipv4Util.IP4_LENGTH), length))).build();
-        buffer.readerIndex(buffer.readerIndex() + PREFIX_F_LENGTH);
-        final BitSet flags = ByteArray.bytesToBitSet(ByteArray.readBytes(buffer, FLAGS_F_LENGTH));
+        buffer.skipBytes(PREFIX_F_LENGTH);
+        final BitArray flags = BitArray.valueOf(buffer, FLAGS_SIZE);
         builder.setProtectionAvailable(flags.get(LPA_F_OFFSET));
         builder.setProtectionInUse(flags.get(LPIU_F_OFFSET));
         builder.setSubobjectType(new IpPrefixCaseBuilder().setIpPrefix(prefix).build());
@@ -72,17 +71,13 @@ public class RROIpv4PrefixSubobjectParser implements RROSubobjectParser, RROSubo
         if (prefix.getIpv6Prefix() != null) {
             new RROIpv6PrefixSubobjectParser().serializeSubobject(subobject, buffer);
         } else {
-            final BitSet flags = new BitSet(FLAGS_F_LENGTH * Byte.SIZE);
-            if (subobject.isProtectionAvailable() != null) {
-                flags.set(LPA_F_OFFSET, subobject.isProtectionAvailable());
-            }
-            if (subobject.isProtectionInUse() != null) {
-                flags.set(LPIU_F_OFFSET, subobject.isProtectionInUse());
-            }
+            final BitArray flags = new BitArray(FLAGS_SIZE);
+            flags.set(LPA_F_OFFSET, subobject.isProtectionAvailable());
+            flags.set(LPIU_F_OFFSET, subobject.isProtectionInUse());
             final ByteBuf body = Unpooled.buffer(CONTENT4_LENGTH);
             Preconditions.checkArgument(prefix.getIpv4Prefix() != null, "Ipv4Prefix is mandatory.");
             writeIpv4Prefix(prefix.getIpv4Prefix(), body);
-            writeBitSet(flags, FLAGS_F_LENGTH, body);
+            flags.toByteBuf(body);
             RROSubobjectUtil.formatSubobject(TYPE, body, buffer);
         }
     }
index 2e9bec2507f807e907ef68b3af052b116732c548..b39d22f1f7e485fd0555b6991acc56b7bfbb5bdb 100644 (file)
@@ -7,17 +7,16 @@
  */
 package org.opendaylight.protocol.pcep.impl.subobject;
 
-import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeBitSet;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeIpv6Prefix;
 
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.RROSubobjectParser;
 import org.opendaylight.protocol.pcep.spi.RROSubobjectSerializer;
 import org.opendaylight.protocol.pcep.spi.RROSubobjectUtil;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.ByteArray;
 import org.opendaylight.protocol.util.Ipv6Util;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
@@ -36,11 +35,11 @@ public class RROIpv6PrefixSubobjectParser implements RROSubobjectParser, RROSubo
     public static final int TYPE = 2;
 
     private static final int PREFIX_F_LENGTH = 1;
-    private static final int FLAGS_F_LENGTH = 1;
+    private static final int FLAGS_SIZE = 8;
 
     private static final int PREFIX_F_OFFSET = Ipv6Util.IPV6_LENGTH;
 
-    private static final int CONTENT_LENGTH = Ipv6Util.IPV6_LENGTH + PREFIX_F_LENGTH + FLAGS_F_LENGTH;
+    private static final int CONTENT_LENGTH = Ipv6Util.IPV6_LENGTH + PREFIX_F_LENGTH + FLAGS_SIZE / Byte.SIZE;
 
     private static final int LPA_F_OFFSET = 7;
     private static final int LPIU_F_OFFSET = 6;
@@ -55,8 +54,8 @@ public class RROIpv6PrefixSubobjectParser implements RROSubobjectParser, RROSubo
         final int length = buffer.getUnsignedByte(PREFIX_F_OFFSET);
         final IpPrefixBuilder prefix = new IpPrefixBuilder().setIpPrefix(new IpPrefix(Ipv6Util.prefixForBytes(ByteArray.readBytes(buffer,
                 Ipv6Util.IPV6_LENGTH), length)));
-        buffer.readerIndex(buffer.readerIndex() + PREFIX_F_LENGTH);
-        final BitSet flags = ByteArray.bytesToBitSet(ByteArray.readBytes(buffer, FLAGS_F_LENGTH));
+        buffer.skipBytes(PREFIX_F_LENGTH);
+        final BitArray flags = BitArray.valueOf(buffer, FLAGS_SIZE);
         builder.setProtectionAvailable(flags.get(LPA_F_OFFSET));
         builder.setProtectionInUse(flags.get(LPIU_F_OFFSET));
         builder.setSubobjectType(new IpPrefixCaseBuilder().setIpPrefix(prefix.build()).build());
@@ -68,17 +67,13 @@ public class RROIpv6PrefixSubobjectParser implements RROSubobjectParser, RROSubo
         Preconditions.checkArgument(subobject.getSubobjectType() instanceof IpPrefixCase, "Unknown subobject instance. Passed %s. Needed IpPrefixCase.", subobject.getSubobjectType().getClass());
         final IpPrefixSubobject specObj = ((IpPrefixCase) subobject.getSubobjectType()).getIpPrefix();
         final IpPrefix prefix = specObj.getIpPrefix();
-        final BitSet flags = new BitSet(FLAGS_F_LENGTH * Byte.SIZE);
-        if (subobject.isProtectionAvailable() != null) {
-            flags.set(LPA_F_OFFSET, subobject.isProtectionAvailable());
-        }
-        if (subobject.isProtectionInUse() != null) {
-            flags.set(LPIU_F_OFFSET, subobject.isProtectionInUse());
-        }
+        final BitArray flags = new BitArray(FLAGS_SIZE);
+        flags.set(LPA_F_OFFSET, subobject.isProtectionAvailable());
+        flags.set(LPIU_F_OFFSET, subobject.isProtectionInUse());
         final ByteBuf body = Unpooled.buffer(CONTENT_LENGTH);
         Preconditions.checkArgument(prefix.getIpv6Prefix() != null, "Ipv6Prefix is mandatory.");
         writeIpv6Prefix(prefix.getIpv6Prefix(), body);
-        writeBitSet(flags, FLAGS_F_LENGTH, body);
+        flags.toByteBuf(body);
         RROSubobjectUtil.formatSubobject(TYPE, body, buffer);
     }
 }
index 2187fe5cc33da7b0892ae51c7b2040c6fdf589ee..b7da1446b7590a51082447659d7816a459c556bf 100644 (file)
@@ -10,13 +10,12 @@ package org.opendaylight.protocol.pcep.impl.subobject;
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.spi.LabelRegistry;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.RROSubobjectParser;
 import org.opendaylight.protocol.pcep.spi.RROSubobjectSerializer;
 import org.opendaylight.protocol.pcep.spi.RROSubobjectUtil;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.reported.route.object.rro.Subobject;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.reported.route.object.rro.SubobjectBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev130820.label.subobject.LabelType;
@@ -29,13 +28,11 @@ public class RROLabelSubobjectParser implements RROSubobjectParser, RROSubobject
 
     public static final int TYPE = 3;
 
-    public static final int RES_F_LENGTH = 1;
+    public static final int FLAGS_SIZE = 8;
 
     public static final int C_TYPE_F_LENGTH = 1;
 
-    public static final int RES_F_OFFSET = 0;
-
-    public static final int C_TYPE_F_OFFSET = RES_F_OFFSET + RES_F_LENGTH;
+    public static final int C_TYPE_F_OFFSET = FLAGS_SIZE / Byte.SIZE;
 
     public static final int HEADER_LENGTH = C_TYPE_F_OFFSET + C_TYPE_F_LENGTH;
 
@@ -55,7 +52,7 @@ public class RROLabelSubobjectParser implements RROSubobjectParser, RROSubobject
             throw new PCEPDeserializerException("Wrong length of array of bytes. Passed: " + buffer.readableBytes() + "; Expected: >"
                     + HEADER_LENGTH + ".");
         }
-        final BitSet reserved = ByteArray.bytesToBitSet(ByteArray.readBytes(buffer, RES_F_LENGTH));
+        final BitArray reserved = BitArray.valueOf(buffer, FLAGS_SIZE);
 
         final short cType = buffer.readUnsignedByte();
 
index a7dcdf61171a41f20c567651c716334976879c56..18b5471fb4bda171d3b4bf6be756f61754d9b125 100644 (file)
@@ -7,18 +7,16 @@
  */
 package org.opendaylight.protocol.pcep.impl.subobject;
 
-import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeBitSet;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeUnsignedInt;
 
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.RROSubobjectParser;
 import org.opendaylight.protocol.pcep.spi.RROSubobjectSerializer;
 import org.opendaylight.protocol.pcep.spi.RROSubobjectUtil;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.reported.route.object.rro.Subobject;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.reported.route.object.rro.SubobjectBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev130820.UnnumberedSubobject;
@@ -33,7 +31,7 @@ public class RROUnnumberedInterfaceSubobjectParser implements RROSubobjectParser
 
     public static final int TYPE = 4;
 
-    private static final int FLAGS_F_LENGTH = 1;
+    private static final int FLAGS_SIZE = 8;
     private static final int RESERVED = 1;
 
     private static final int CONTENT_LENGTH = 10;
@@ -49,11 +47,11 @@ public class RROUnnumberedInterfaceSubobjectParser implements RROSubobjectParser
                     + CONTENT_LENGTH + ".");
         }
         final SubobjectBuilder builder = new SubobjectBuilder();
-        final BitSet flags = ByteArray.bytesToBitSet(ByteArray.readBytes(buffer, FLAGS_F_LENGTH));
+        final BitArray flags = BitArray.valueOf(buffer, FLAGS_SIZE);
         builder.setProtectionAvailable(flags.get(LPA_F_OFFSET));
         builder.setProtectionInUse(flags.get(LPIU_F_OFFSET));
         final UnnumberedBuilder ubuilder = new UnnumberedBuilder();
-        buffer.readerIndex(buffer.readerIndex() + RESERVED);
+        buffer.skipBytes(RESERVED);
         ubuilder.setRouterId(buffer.readUnsignedInt());
         ubuilder.setInterfaceId(buffer.readUnsignedInt());
         builder.setSubobjectType(new UnnumberedCaseBuilder().setUnnumbered(ubuilder.build()).build());
@@ -64,15 +62,11 @@ public class RROUnnumberedInterfaceSubobjectParser implements RROSubobjectParser
     public void serializeSubobject(final Subobject subobject, final ByteBuf buffer) {
         Preconditions.checkArgument(subobject.getSubobjectType() instanceof UnnumberedCase, "Unknown subobject instance. Passed %s. Needed UnnumberedCase.", subobject.getSubobjectType().getClass());
         final UnnumberedSubobject specObj = ((UnnumberedCase) subobject.getSubobjectType()).getUnnumbered();
-        final BitSet flags = new BitSet(FLAGS_F_LENGTH * Byte.SIZE);
-        if (subobject.isProtectionAvailable() != null) {
-            flags.set(LPA_F_OFFSET, subobject.isProtectionAvailable());
-        }
-        if (subobject.isProtectionInUse() != null) {
-            flags.set(LPIU_F_OFFSET, subobject.isProtectionInUse());
-        }
+        final BitArray flags = new BitArray(FLAGS_SIZE);
+        flags.set(LPA_F_OFFSET, subobject.isProtectionAvailable());
+        flags.set(LPIU_F_OFFSET, subobject.isProtectionInUse());
         final ByteBuf body = Unpooled.buffer(CONTENT_LENGTH);
-        writeBitSet(flags, FLAGS_F_LENGTH, body);
+        flags.toByteBuf(body);
         body.writeZero(RESERVED);
         Preconditions.checkArgument(specObj.getRouterId() != null, "RouterId is mandatory.");
         writeUnsignedInt(specObj.getRouterId(), body);
index 0fc66aa81d3c502b31f61cae4bc46355f6ca8fac..01499543cb3f4ed3dbb1d7a8071bea643c10eb47 100644 (file)
@@ -53,7 +53,7 @@ public class XROIpv4PrefixSubobjectParser implements XROSubobjectParser, XROSubo
         final IpPrefixBuilder prefix = new IpPrefixBuilder().setIpPrefix(new IpPrefix(Ipv4Util.prefixForBytes(ByteArray.readBytes(buffer,
                 Ipv4Util.IP4_LENGTH), length)));
         builder.setSubobjectType(new IpPrefixCaseBuilder().setIpPrefix(prefix.build()).build());
-        buffer.readerIndex(buffer.readerIndex() + PREFIX_F_LENGTH);
+        buffer.skipBytes(PREFIX_F_LENGTH);
         builder.setAttribute(Attribute.forValue(buffer.readUnsignedByte()));
         return builder.build();
     }
index 39fc55c670bbc603c17ce04fcdbec039ac4804e7..0cf6cd631d6aca1a5ca10bfebcc815dbba14f065 100644 (file)
@@ -53,7 +53,7 @@ public class XROIpv6PrefixSubobjectParser implements XROSubobjectParser, XROSubo
         final IpPrefixBuilder prefix = new IpPrefixBuilder().setIpPrefix(new IpPrefix(Ipv6Util.prefixForBytes(ByteArray.readBytes(buffer,
                 Ipv6Util.IPV6_LENGTH), length)));
         builder.setSubobjectType(new IpPrefixCaseBuilder().setIpPrefix(prefix.build()).build());
-        buffer.readerIndex(buffer.readerIndex() + PREFIX_F_LENGTH);
+        buffer.skipBytes(PREFIX_F_LENGTH);
         builder.setAttribute(Attribute.forValue(buffer.readUnsignedByte()));
         return builder.build();
     }
index 84ad0f116e05c866bc74208ffb90630662208f37..f8822f8efb60a1fdbfdf62e7acbba3914a19e6b5 100644 (file)
@@ -10,13 +10,11 @@ package org.opendaylight.protocol.pcep.impl.tlv;
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.TlvParser;
 import org.opendaylight.protocol.pcep.spi.TlvSerializer;
 import org.opendaylight.protocol.pcep.spi.TlvUtil;
-import org.opendaylight.protocol.util.ByteArray;
-import org.opendaylight.protocol.util.ByteBufWriteUtil;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.NoPathVectorTlv.Flags;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Tlv;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrep.message.pcrep.message.replies.result.failure._case.no.path.tlvs.NoPathVector;
@@ -29,7 +27,7 @@ public class NoPathVectorTlvParser implements TlvParser, TlvSerializer {
 
     public static final int TYPE = 1;
 
-    private static final int FLAGS_F_LENGTH = 4;
+    private static final int FLAGS_SIZE = 32;
 
     private static final int REACHABLITY_PROBLEM = 24;
     private static final int NO_GCO_SOLUTION = 25;
@@ -45,11 +43,11 @@ public class NoPathVectorTlvParser implements TlvParser, TlvSerializer {
         if (buffer == null) {
             return null;
         }
-        if (buffer.readableBytes() != FLAGS_F_LENGTH) {
+        if (buffer.readableBytes() != FLAGS_SIZE / Byte.SIZE) {
             throw new PCEPDeserializerException("Wrong length of array of bytes. Passed: " + buffer.readableBytes() + "; Expected: >="
-                    + FLAGS_F_LENGTH + ".");
+                    + FLAGS_SIZE / Byte.SIZE + ".");
         }
-        final BitSet flags = ByteArray.bytesToBitSet(ByteArray.readAllBytes(buffer));
+        final BitArray flags = BitArray.valueOf(buffer, FLAGS_SIZE);
         return new NoPathVectorBuilder().setFlags(
                 new Flags(flags.get(CHAIN_UNAVAILABLE), flags.get(NO_GCO_MIGRATION_PATH), flags.get(NO_GCO_SOLUTION), flags.get(REACHABLITY_PROBLEM), flags.get(PATH_KEY), flags.get(PCE_UNAVAILABLE), flags.get(UNKNOWN_DEST), flags.get(UNKNOWN_SRC))).build();
     }
@@ -59,33 +57,17 @@ public class NoPathVectorTlvParser implements TlvParser, TlvSerializer {
         Preconditions.checkArgument(tlv instanceof NoPathVector, "NoPathVectorTlv is mandatory.");
         final NoPathVector noPath = (NoPathVector) tlv;
         final ByteBuf body = Unpooled.buffer();
-        final BitSet flags = new BitSet(FLAGS_F_LENGTH * Byte.SIZE);
-        Flags f = noPath.getFlags();
-        if (f.isP2mpUnreachable() != null) {
-            flags.set(REACHABLITY_PROBLEM, f.isP2mpUnreachable());
-        }
-        if (f.isNoGcoSolution() != null) {
-            flags.set(NO_GCO_SOLUTION, f.isNoGcoSolution());
-        }
-        if (f.isNoGcoMigration() != null) {
-            flags.set(NO_GCO_MIGRATION_PATH, f.isNoGcoMigration());
-        }
-        if (f.isPathKey() != null) {
-            flags.set(PATH_KEY, f.isPathKey());
-        }
-        if (f.isChainUnavailable() != null) {
-            flags.set(CHAIN_UNAVAILABLE, f.isChainUnavailable());
-        }
-        if (f.isUnknownSource() != null) {
-            flags.set(UNKNOWN_SRC, f.isUnknownSource());
-        }
-        if (f.isUnknownDestination() != null) {
-            flags.set(UNKNOWN_DEST, f.isUnknownDestination());
-        }
-        if (f.isPceUnavailable() != null) {
-            flags.set(PCE_UNAVAILABLE, f.isPceUnavailable());
-        }
-        ByteBufWriteUtil.writeBitSet(flags, FLAGS_F_LENGTH, body);
+        final BitArray flags = new BitArray(FLAGS_SIZE);
+        final Flags f = noPath.getFlags();
+        flags.set(REACHABLITY_PROBLEM, f.isP2mpUnreachable());
+        flags.set(NO_GCO_SOLUTION, f.isNoGcoSolution());
+        flags.set(NO_GCO_MIGRATION_PATH, f.isNoGcoMigration());
+        flags.set(PATH_KEY, f.isPathKey());
+        flags.set(CHAIN_UNAVAILABLE, f.isChainUnavailable());
+        flags.set(UNKNOWN_SRC, f.isUnknownSource());
+        flags.set(UNKNOWN_DEST, f.isUnknownDestination());
+        flags.set(PCE_UNAVAILABLE, f.isPceUnavailable());
+        flags.toByteBuf(body);
         TlvUtil.formatTlv(TYPE, body, buffer);
     }
 }
index c124e7e649953ec90ad326bbd4ea1dfb42424af8..717d865d0d072079b8c263dcb22988b292306573 100644 (file)
@@ -5,7 +5,6 @@
  * 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.pcep.segment.routing;
 
 import static org.opendaylight.protocol.pcep.segment.routing.SrSubobjectParserUtil.BITSET_LENGTH;
@@ -13,11 +12,11 @@ import static org.opendaylight.protocol.pcep.segment.routing.SrSubobjectParserUt
 import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.spi.EROSubobjectParser;
 import org.opendaylight.protocol.pcep.spi.EROSubobjectSerializer;
 import org.opendaylight.protocol.pcep.spi.EROSubobjectUtil;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev150112.SrEroSubobject;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev150112.SrSubobject;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev150112.add.lsp.input.arguments.ero.subobject.subobject.type.SrEroTypeBuilder;
@@ -45,19 +44,14 @@ public class SrEroSubobjectParser implements EROSubobjectParser, EROSubobjectSer
         if (srEroSubobject.isMFlag() != null && srEroSubobject.isMFlag() && srEroSubobject.getSid() != null) {
             builder.setSid(srEroSubobject.getSid() << MPLS_LABEL_OFFSET);
         }
-
-        final BitSet bits = new BitSet(BITSET_LENGTH);
-        if (srEroSubobject.isMFlag() != null) {
-            bits.set(M_FLAG_POSITION, srEroSubobject.isMFlag());
-        }
-        if (srEroSubobject.isCFlags() != null) {
-            bits.set(C_FLAG_POSITION, srEroSubobject.isCFlags());
-        }
+        final BitArray bits = new BitArray(BITSET_LENGTH);
+        bits.set(M_FLAG_POSITION, srEroSubobject.isMFlag());
+        bits.set(C_FLAG_POSITION, srEroSubobject.isCFlags());
         if (srEroSubobject.getSid() == null) {
-            bits.set(S_FLAG_POSITION);
+            bits.set(S_FLAG_POSITION, Boolean.TRUE);
         }
         if (srEroSubobject.getNai() == null) {
-            bits.set(F_FLAG_POSITION);
+            bits.set(F_FLAG_POSITION, Boolean.TRUE);
         }
         final ByteBuf body = SrSubobjectParserUtil.serializeSrSubobject(builder.build(), bits);
         EROSubobjectUtil.formatSubobject(TYPE, subobject.isLoose(), body, buffer);
@@ -70,11 +64,10 @@ public class SrEroSubobjectParser implements EROSubobjectParser, EROSubobjectSer
         if (buffer.readableBytes() <= SrSubobjectParserUtil.MINIMAL_LENGTH) {
             throw new PCEPDeserializerException("Wrong length of array of bytes. Passed: " + buffer.readableBytes() + ";");
         }
-
-        final BitSet flags = new BitSet(BITSET_LENGTH);
-        final SrSubobject srSubobject = SrSubobjectParserUtil.parseSrSubobject(buffer, new Function<BitSet, Void>() {
+        final BitArray flags = new BitArray(BITSET_LENGTH);
+        final SrSubobject srSubobject = SrSubobjectParserUtil.parseSrSubobject(buffer, new Function<BitArray, Void>() {
             @Override
-            public Void apply(final BitSet input) {
+            public Void apply(final BitArray input) {
                 flags.set(C_FLAG_POSITION, input.get(C_FLAG_POSITION));
                 flags.set(M_FLAG_POSITION, input.get(M_FLAG_POSITION));
                 return null;
@@ -86,7 +79,6 @@ public class SrEroSubobjectParser implements EROSubobjectParser, EROSubobjectSer
         if (srEroSubobjectBuilder.isMFlag() != null && srEroSubobjectBuilder.isMFlag() && srEroSubobjectBuilder.getSid() != null) {
             srEroSubobjectBuilder.setSid(srEroSubobjectBuilder.getSid() >> MPLS_LABEL_OFFSET);
         }
-
         final SubobjectBuilder subobjectBuilder = new SubobjectBuilder();
         subobjectBuilder.setLoose(loose);
         subobjectBuilder.setSubobjectType(srEroSubobjectBuilder.build());
index 8496698b50ffbdb8db134dc088d290f93f79eacf..eae3b391e28e00e61b5a505e4ce2325a3f966978 100644 (file)
@@ -14,11 +14,11 @@ import static org.opendaylight.protocol.pcep.segment.routing.SrSubobjectParserUt
 import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
 import org.opendaylight.protocol.pcep.spi.RROSubobjectParser;
 import org.opendaylight.protocol.pcep.spi.RROSubobjectSerializer;
 import org.opendaylight.protocol.pcep.spi.RROSubobjectUtil;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev150112.SrRroSubobject;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev150112.SrSubobject;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev150112.add.lsp.input.arguments.rro.subobject.subobject.type.SrRroTypeBuilder;
@@ -39,12 +39,12 @@ public class SrRroSubobjectParser implements RROSubobjectParser, RROSubobjectSer
                         .getClass());
 
         final SrRroSubobject srRroSubobject = (SrRroSubobject) subobject.getSubobjectType();
-        final BitSet bits = new BitSet(BITSET_LENGTH);
+        final BitArray bits = new BitArray(BITSET_LENGTH);
         if (srRroSubobject.getSid() == null) {
-            bits.set(S_FLAG_POSITION);
+            bits.set(S_FLAG_POSITION, Boolean.TRUE);
         }
         if (srRroSubobject.getNai() == null) {
-            bits.set(F_FLAG_POSITION);
+            bits.set(F_FLAG_POSITION, Boolean.TRUE);
         }
         final ByteBuf body = SrSubobjectParserUtil.serializeSrSubobject(srRroSubobject, bits);
         RROSubobjectUtil.formatSubobject(TYPE, body, buffer);
@@ -58,9 +58,9 @@ public class SrRroSubobjectParser implements RROSubobjectParser, RROSubobjectSer
             throw new PCEPDeserializerException("Wrong length of array of bytes. Passed: " + buffer.readableBytes() + ";");
         }
 
-        final SrSubobject srSubobject = SrSubobjectParserUtil.parseSrSubobject(buffer, new Function<BitSet, Void>() {
+        final SrSubobject srSubobject = SrSubobjectParserUtil.parseSrSubobject(buffer, new Function<BitArray, Void>() {
             @Override
-            public Void apply(final BitSet input) {
+            public Void apply(final BitArray input) {
                 return null;
             }
         }, F_FLAG_POSITION, S_FLAG_POSITION);
index da03eecaffb8660e4a6c119980676d65c9175ff7..df604152e332bffcc1c136f2dbf2439c5c8c79e0 100644 (file)
@@ -5,10 +5,8 @@
  * 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.pcep.segment.routing;
 
-import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeBitSet;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeIpv4Address;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeIpv6Address;
 import static org.opendaylight.protocol.util.ByteBufWriteUtil.writeUnsignedByte;
@@ -18,9 +16,8 @@ import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import java.util.BitSet;
 import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.ByteBufWriteUtil;
 import org.opendaylight.protocol.util.Ipv4Util;
 import org.opendaylight.protocol.util.Ipv6Util;
@@ -42,20 +39,18 @@ final class SrSubobjectParserUtil {
     public static final int MINIMAL_LENGTH = 4;
     public static final int BITSET_LENGTH = 8;
 
-    private static final int FLAGS_OFFSET = 1;
     private static final int SID_TYPE_BITS_OFFSET = 4;
 
     private SrSubobjectParserUtil() {
         throw new UnsupportedOperationException();
     }
 
-    public static ByteBuf serializeSrSubobject(final SrSubobject srSubobject, final BitSet bits) {
+    public static ByteBuf serializeSrSubobject(final SrSubobject srSubobject, final BitArray bits) {
         Preconditions.checkArgument(srSubobject.getNai() != null || srSubobject.getSid() != null,
                 "Both SID and NAI are absent in SR subobject.");
         final ByteBuf body = Unpooled.buffer(MINIMAL_LENGTH);
         writeUnsignedByte((short)(srSubobject.getSidType().getIntValue() << SID_TYPE_BITS_OFFSET), body);
-
-        writeBitSet(bits, FLAGS_OFFSET, body);
+        bits.toByteBuf(body);
 
         if (srSubobject.getSid() != null) {
             writeUnsignedInt(srSubobject.getSid(), body);
@@ -91,12 +86,12 @@ final class SrSubobjectParserUtil {
         return body;
     }
 
-    public static SrSubobject parseSrSubobject(final ByteBuf buffer, final Function<BitSet, Void> getFlags, final int fPosition, final int sPosition)
+    public static SrSubobject parseSrSubobject(final ByteBuf buffer, final Function<BitArray, Void> getFlags, final int fPosition, final int sPosition)
             throws PCEPDeserializerException {
         final int sidTypeByte = buffer.readByte() >> SID_TYPE_BITS_OFFSET;
         final SidType sidType = SidType.forValue(sidTypeByte);
 
-        final BitSet bitSet = ByteArray.bytesToBitSet(new byte[] { buffer.readByte() });
+        final BitArray bitSet = BitArray.valueOf(buffer.readByte());
         getFlags.apply(bitSet);
         final boolean f = bitSet.get(fPosition);
         final boolean s = bitSet.get(sPosition);
index 93d548cd056a47cdd76eaa097e532d0cd34c5289..e4929b2aa7488b813546f465b440c13310ee4546 100644 (file)
@@ -13,10 +13,10 @@ import com.google.common.primitives.UnsignedBytes;
 import io.netty.buffer.ByteBuf;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.BitSet;
 import java.util.Collections;
 import java.util.List;
 import javax.annotation.Nullable;
+import org.opendaylight.protocol.util.BitArray;
 import org.opendaylight.protocol.util.ByteArray;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.iana.rev130816.EnterpriseNumber;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.PcerrBuilder;
@@ -37,17 +37,15 @@ public abstract class AbstractMessageParser implements MessageParser, MessageSer
     private static final int COMMON_OBJECT_HEADER_LENGTH = 4;
 
     private static final int OT_SF_LENGTH = 4;
-    private static final int FLAGS_SF_LENGTH = 4;
     /*
      * offsets of fields inside of multi-field in bits
      */
     private static final int OT_SF_OFFSET = 0;
-    private static final int FLAGS_SF_OFFSET = OT_SF_OFFSET + OT_SF_LENGTH;
     /*
      * flags offsets inside multi-filed
      */
-    private static final int P_FLAG_OFFSET = 6;
-    private static final int I_FLAG_OFFSET = 7;
+    private static final int PROCESSED = 6;
+    private static final int IGNORED = 7;
 
     private final ObjectRegistry registry;
     private final VendorInformationObjectRegistry viRegistry;
@@ -85,10 +83,8 @@ public abstract class AbstractMessageParser implements MessageParser, MessageSer
             final int objClass = bytes.readUnsignedByte();
 
             final byte flagsByte = bytes.readByte();
+            final BitArray flags = BitArray.valueOf(flagsByte);
             final int objType = UnsignedBytes.toInt(ByteArray.copyBitsRange(flagsByte, OT_SF_OFFSET, OT_SF_LENGTH));
-            final byte[] flagsBytes = { ByteArray.copyBitsRange(flagsByte, FLAGS_SF_OFFSET, FLAGS_SF_LENGTH) };
-            final BitSet flags = ByteArray.bytesToBitSet(flagsBytes);
-
             final int objLength = bytes.readUnsignedShort();
 
             if (bytes.readableBytes() < objLength - COMMON_OBJECT_HEADER_LENGTH) {
@@ -98,7 +94,7 @@ public abstract class AbstractMessageParser implements MessageParser, MessageSer
             // copy bytes for deeper parsing
             final ByteBuf bytesToPass = bytes.readSlice(objLength - COMMON_OBJECT_HEADER_LENGTH);
 
-            final ObjectHeader header = new ObjectHeaderImpl(flags.get(P_FLAG_OFFSET), flags.get(I_FLAG_OFFSET));
+            final ObjectHeader header = new ObjectHeaderImpl(flags.get(PROCESSED), flags.get(IGNORED));
 
             if (VendorInformationUtil.isVendorInformationObject(objClass, objType)) {
                 Preconditions.checkState(this.viRegistry != null);
index ec9a33a1e5a0052001c6b9f592e7fe704211e9c1..1144a8b22f059f738c71985d4912903d422c5dc2 100644 (file)
@@ -8,30 +8,24 @@
 package org.opendaylight.protocol.pcep.spi;
 
 import io.netty.buffer.ByteBuf;
-import java.util.BitSet;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 
 public final class LabelUtil {
 
-    private static final int RES_F_LENGTH = 1;
+    private static final int FLAGS_SIZE = 8;
 
-    private static final int U_FLAG_OFFSET = 0;
-
-    private static final int G_FLAG_OFFSET = 7;
+    private static final int UNIDIRECTIONAL = 0;
+    private static final int GLOBAL = 7;
 
     private LabelUtil() {
         throw new UnsupportedOperationException();
     }
 
     public static void formatLabel(final int type, final Boolean unidirectional, final Boolean global, final ByteBuf body, final ByteBuf buffer) {
-        final BitSet reserved = new BitSet(RES_F_LENGTH * Byte.SIZE);
-        if (unidirectional != null) {
-            reserved.set(U_FLAG_OFFSET, unidirectional);
-        }
-        if (global != null) {
-            reserved.set(G_FLAG_OFFSET, global);
-        }
-        buffer.writeBytes(ByteArray.bitSetToBytes(reserved, RES_F_LENGTH));
+        final BitArray reserved = new BitArray(FLAGS_SIZE);
+        reserved.set(UNIDIRECTIONAL, unidirectional);
+        reserved.set(GLOBAL, global);
+        reserved.toByteBuf(buffer);
         buffer.writeByte(type);
         buffer.writeBytes(body);
     }
index f96b9ad71447f3803e5aa17d8f8a26c78c5ab3c2..86f6779422b4e67c744cb0d25c9ad726f8ad6c2d 100644 (file)
@@ -8,19 +8,18 @@
 package org.opendaylight.protocol.pcep.spi;
 
 import io.netty.buffer.ByteBuf;
-import java.util.BitSet;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.BitArray;
 
 public final class ObjectUtil {
 
     private static final int HEADER_SIZE = 4;
 
-    private static final int OT_SF_LENGTH = 4;
+    private static final int FLAGS_SIZE = 4;
     /*
      * flags offsets inside multi-field
      */
-    private static final int P_FLAG_OFFSET = 6;
-    private static final int I_FLAG_OFFSET = 7;
+    private static final int PROCESSED = 2;
+    private static final int IGNORED = 3;
 
     private ObjectUtil() {
         throw new UnsupportedOperationException();
@@ -29,15 +28,11 @@ public final class ObjectUtil {
     public static void formatSubobject(final int objectType, final int objectClass, final Boolean processingRule, final Boolean ignore,
         final ByteBuf body, final ByteBuf out) {
         out.writeByte(objectClass);
-        BitSet flags = new BitSet(Byte.SIZE);
-        if (ignore != null) {
-            flags.set(I_FLAG_OFFSET, ignore);
-        }
-        if (processingRule != null) {
-            flags.set(P_FLAG_OFFSET, processingRule);
-        }
-        byte[] flagB = ByteArray.bitSetToBytes(flags, 1);
-        int typeByte = objectType << OT_SF_LENGTH | flagB[0];
+        final BitArray flags = new BitArray(FLAGS_SIZE);
+        flags.set(IGNORED, ignore);
+        flags.set(PROCESSED, processingRule);
+        final byte flagB = flags.toByte();
+        final int typeByte = objectType << FLAGS_SIZE | flagB;
         out.writeByte(typeByte);
         out.writeShort(body.writerIndex() + HEADER_SIZE);
         out.writeBytes(body);
diff --git a/util/src/main/java/org/opendaylight/protocol/util/BitArray.java b/util/src/main/java/org/opendaylight/protocol/util/BitArray.java
new file mode 100644 (file)
index 0000000..347a11e
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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.util;
+
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.UnsignedBytes;
+import io.netty.buffer.ByteBuf;
+
+/**
+ * This class was created to minimize usage of Java BitSet class, as this one
+ * is hard to use within specifics of network protocols. Uses network byte
+ * order.
+ */
+public final class BitArray {
+
+    private final int size;
+
+    private final byte[] backingArray;
+
+    /**
+     * Creates a BitArray with fixed size of bits. For sizes smaller than
+     * 8 the whole byte is allocated.
+     *
+     * @param size Number of bits relevant for this BitArray. Needs to be
+     * greater than 0.
+     */
+    public BitArray(final int size) {
+        Preconditions.checkArgument(size >= 1, "Minimum size is 1 bit.");
+        this.size = size;
+        this.backingArray = new byte[calculateBytes(size)];
+    }
+
+    private BitArray(final byte[] backingArray, final int size) {
+        Preconditions.checkNotNull(backingArray, "Byte Array cannot be null");
+        this.backingArray = backingArray;
+        this.size = size;
+    }
+
+    /**
+     * Returns a new BitArray created from bytes from given ByteBuf.
+     *
+     * @param buffer ByteBuf, whose readerIndex will be moved by
+     * minimum number of bytes required for the bit size.
+     * @param size Number of bits to be allocated in BitArray
+     * @return new BitArray
+     */
+    public static BitArray valueOf(final ByteBuf buffer, final int size) {
+        Preconditions.checkArgument(size >= 1, "Minimum size is 1 bit.");
+        Preconditions.checkNotNull(buffer, "Byte Array cannot be null");
+        final byte[] b = new byte[calculateBytes(size)];
+        buffer.readBytes(b, 0, b.length);
+        return new BitArray(b, size);
+    }
+
+    /**
+     * Returns a new BitArray with given byte array as backing
+     * array.
+     *
+     * @param bytes byte array
+     * @return new BitArray
+     */
+    public static BitArray valueOf(final byte[] bytes) {
+        return new BitArray(bytes, bytes.length);
+    }
+
+    /**
+     * Returns new BitArray with given byte as backing
+     * array.
+     *
+     * @param b unsigned byte
+     * @return new BitArray
+     */
+    public static BitArray valueOf(final byte b) {
+        return new BitArray(new byte[] {b}, Byte.SIZE);
+    }
+
+    /**
+     * Sets bit on given position to the value given as parameter.
+     * Checks for null value. Index is counted from the rightmost
+     * bit as 0 to size -1 being the leftmost bit.
+     *
+     * @param index position of bit that will be set
+     * @param value Boolean
+     */
+    public void set(final int index, final Boolean value) {
+        Preconditions.checkArgument(index < this.size, "Index out of bounds.");
+        if (value == null || value.equals(Boolean.FALSE)) {
+            return;
+        }
+        final int pos = calculatePosition(index);
+        final byte b = this.backingArray[pos];
+        this.backingArray[pos] = (byte) (UnsignedBytes.toInt(b) | mask(index));
+    }
+
+    /**
+     * Returns boolean value for a bit on specific position.
+     * Index is counted from the rightmost bit as 0 to
+     * size -1 being the leftmost bit.
+     *
+     * @param index position of bit
+     * @return boolean value
+     */
+    public boolean get(final int index) {
+        Preconditions.checkArgument(index < this.size, "Index out of bounds.");
+        final byte b = this.backingArray[calculatePosition(index)];
+        return ((byte) (UnsignedBytes.toInt(b) & mask(index))) != 0;
+    }
+
+    /**
+     * Returns the backing byte array of this bitset
+     *
+     * @return byte[]
+     */
+    public byte[] array() {
+        return this.backingArray.clone();
+    }
+
+    /**
+     * If possible, returns one byte as backing array.
+     *
+     * @return byte
+     */
+    public byte toByte() {
+        Preconditions.checkArgument(Byte.SIZE >= this.size, "Cannot put backing array to a single byte.");
+        return this.backingArray[0];
+    }
+
+    /**
+     * Writes backing array to given ByteBuf, even if the backing array is
+     * empty, to preserve the number of allocated bits.
+     *
+     * @param buffer ByteBuf
+     */
+    public void toByteBuf(final ByteBuf buffer) {
+        buffer.writeBytes(this.backingArray);
+    }
+
+    /**
+     * Calculates the size in bytes necessary for given number of bits.
+     *
+     * @param size size
+     * @return minimum byte size to contain the position of the bit
+     */
+    private static int calculateBytes(final int size) {
+        return size/Byte.SIZE + (size % Byte.SIZE == 0 ? 0 : 1);
+    }
+
+    /**
+     * Calculates which byte in byte array is going to be affected.
+     *
+     * @param index index of the bit to be changed
+     * @return position in byte array
+     */
+    private int calculatePosition(final int index) {
+        final int offset = (calculateBytes(this.size) * Byte.SIZE) - this.size;
+        return (index + offset) / Byte.SIZE;
+    }
+
+    /**
+     * Returns a byte where only one bit is set
+     *
+     * @param index bit index within full byte array
+     * @return byte with one bit set
+     */
+    private byte mask(final int index) {
+        return (byte) (1 << ((this.size -1 - index) % Byte.SIZE));
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder b = new StringBuilder("BitArray [");
+        for (int i = 0; i < this.backingArray.length; i++) {
+            b.append(Integer.toBinaryString(UnsignedBytes.toInt(this.backingArray[i])));
+            if (i != this.backingArray.length - 1) {
+                b.append(' ');
+            }
+        }
+        b.append(']');
+        return b.toString();
+    }
+}
index d5e7ecd87261e1fbe7449d6a982ca933dc1a953e..83b6d863768ba95539c2bb75a8200ee17d6e7b17 100644 (file)
@@ -173,6 +173,7 @@ public final class ByteArray {
      * @param b byte to be parsed
      * @return array of booleans with size of 8
      */
+    @Deprecated
     public static boolean[] parseBits(final byte b) {
         final boolean[] bits = new boolean[Byte.SIZE];
         int j = 0;
@@ -189,6 +190,7 @@ public final class ByteArray {
      * @param bytes array of bytes to be parsed
      * @return BitSet with length = bytes.length * Byte.SIZE
      */
+    @Deprecated
     public static BitSet bytesToBitSet(final byte[] bytes) {
         final BitSet bitSet = new BitSet(bytes.length * Byte.SIZE);
         for (int bytesIter = 0; bytesIter < bytes.length; bytesIter++) {
@@ -207,6 +209,7 @@ public final class ByteArray {
      * @param returnedLength Length of returned array. Overlapping flags are truncated.
      * @return parsed array of bytes with length of bitSet.length / Byte.SIZE
      */
+    @Deprecated
     public static byte[] bitSetToBytes(final BitSet bitSet, final int returnedLength) {
         final byte[] bytes = new byte[returnedLength];
 
diff --git a/util/src/test/java/org/opendaylight/protocol/util/BitArrayTest.java b/util/src/test/java/org/opendaylight/protocol/util/BitArrayTest.java
new file mode 100644 (file)
index 0000000..dfef484
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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.util;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class BitArrayTest {
+
+    @Test
+    public void testCreateBitArray() {
+        Assert.assertArrayEquals(new byte[1], new BitArray(5).array());
+        Assert.assertArrayEquals(new byte[3], new BitArray(23).array());
+        Assert.assertArrayEquals(new byte[3], new BitArray(24).array());
+        Assert.assertArrayEquals(new byte[4], new BitArray(25).array());
+
+        final byte[] a = new byte[] {1, 2, 3, 4};
+        Assert.assertArrayEquals(a, BitArray.valueOf(a).array());
+
+        final byte b = 44;
+        Assert.assertEquals(b, BitArray.valueOf(b).toByte());
+
+        final ByteBuf buf = Unpooled.wrappedBuffer(a);
+        Assert.assertArrayEquals(new byte[] {1, 2}, BitArray.valueOf(buf, 12).array());
+
+        final ByteBuf res = Unpooled.buffer();
+        final BitArray i = BitArray.valueOf(a);
+        i.toByteBuf(res);
+        Assert.assertArrayEquals(new byte[] {1, 2, 3, 4}, ByteArray.readAllBytes(res));
+    }
+
+    @Test
+    public void testSetAndGet() {
+        final BitArray ba = new BitArray(10);
+        ba.set(0, null);
+        ba.set(1, Boolean.TRUE);
+        ba.set(2, Boolean.FALSE);
+        ba.set(3, Boolean.TRUE);
+        ba.set(7, Boolean.TRUE);
+        ba.set(8, Boolean.TRUE);
+        ba.set(9, Boolean.TRUE);
+
+        Assert.assertEquals("BitArray [1 1000111]", ba.toString());
+
+        Assert.assertFalse(ba.get(0));
+        Assert.assertTrue(ba.get(1));
+        Assert.assertFalse(ba.get(2));
+        Assert.assertTrue(ba.get(3));
+        Assert.assertTrue(ba.get(7));
+        Assert.assertTrue(ba.get(8));
+        Assert.assertTrue(ba.get(9));
+    }
+}