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;
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;
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();
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();
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;
*/
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;
}
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
}
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));
}
}
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();
}
}
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() {
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;
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;
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;
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);
}
}
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;
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;
}
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));
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);
}
}
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;
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;
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);
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();
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;
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();
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)));
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;
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)));
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());
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;
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;
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());
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();
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);
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();
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;
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()));
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());
}
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));
}
}
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));
}
}
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;
}
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 {
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;
}
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 {
<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>
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+
+}
private final AsNumber asNumber;
private final Ipv4Address bgpId;
private final BGPPeerRegistry peerRegistry;
+ private final ChannelOutputLimiter limiter;
private BGPSessionStats sessionStats;
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;
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();
}
}
- 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();
* @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));
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();
}
public synchronized void resetSessionStats() {
this.sessionStats.resetStats();
}
+
+ ChannelOutputLimiter getLimiter() {
+ return limiter;
+ }
}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
@Override
protected boolean writePDU(final Update pdu) {
- session.sendMessage(pdu);
+ session.writeAndFlush(pdu);
return session.isWritable();
}
--- /dev/null
+/*
+ * 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);
+ }
+}
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;
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 {
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();
}
@Override
- public void sendMessage(final Notification msg) {
+ public void writeAndFlush(final Notification msg) {
this.setLastMessageSentAt(System.nanoTime());
this.client.onMessage(this, msg);
}
<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>
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
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;
* 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
*/
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
--- /dev/null
+/*
+ * 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);
+
+}
--- /dev/null
+/*
+ * 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();
+}
*/
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,
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);
}
}
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));
+ }
}
<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>
TestHelper.mdSalCoreBundles(),
TestHelper.bindingAwareSalBundles(), TestHelper.configMinumumBundles(), TestHelper.baseModelBundles(),
- TestHelper.flowCapableModelBundles(), TestHelper.junitAndMockitoBundles());
+ TestHelper.junitAndMockitoBundles());
}
private Option pcepModules() {
<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>
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;
*/
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);
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());
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;
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);
}
*/
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;
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();
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);
*/
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;
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());
}
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);
}
}
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;
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);
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());
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);
}
*/
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;
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;
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;
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 {
} 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();
}
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();
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.");
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);
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());
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);
*/
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;
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;
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();
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);
}
}
/* 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));
}
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();
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);
}
}
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());
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());
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();
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();
*/
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;
/*
* 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
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();
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);
*/
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;
/*
* 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;
/*
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());
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);
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;
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;
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);
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);
*/
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;
/*
* 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;
/*
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());
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);
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());
* 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;
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;
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;
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);
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());
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;
/*
* 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
@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());
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);
*/
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;
/*
* field lengths in bytes
*/
- private static final int FLAGS_F_LENGTH = 3;
+ private static final int FLAGS_SIZE = 24;
/*
* fields offsets in bytes
/*
* 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 {
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()) {
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.";
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;
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;
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());
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());
*/
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;
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;
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());
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);
}
}
*/
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;
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;
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());
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);
}
}
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;
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;
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();
*/
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;
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;
+ 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());
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);
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();
}
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();
}
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;
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;
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();
}
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);
}
}
* 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;
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;
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);
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;
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());
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;
.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);
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);
* 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;
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;
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);
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);
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;
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;
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) {
// 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);
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);
}
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();
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);
--- /dev/null
+/*
+ * 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();
+ }
+}
* @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;
* @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++) {
* @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];
--- /dev/null
+/*
+ * 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));
+ }
+}